/**
   * Makes sure we handle the shutdown gracefully. Shuts off power regardless of radio and bluetooth
   * state if the alloted time has passed.
   */
  public void run() {
    BroadcastReceiver br =
        new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
            // We don't allow apps to cancel this, so ignore the result.
            actionDone();
          }
        };

    /*
     * Write a system property in case the system_server reboots before we
     * get to the actual hardware restart. If that happens, we'll retry at
     * the beginning of the SystemServer startup.
     */
    {
      String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
      SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
    }

    /*
     * If we are rebooting into safe mode, write a system property
     * indicating so.
     */
    if (mRebootSafeMode) {
      SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
    }

    Log.i(TAG, "Sending shutdown broadcast...");

    // First send the high-level shut down broadcast.
    mActionDone = false;
    mContext.sendOrderedBroadcastAsUser(
        new Intent(Intent.ACTION_SHUTDOWN), UserHandle.ALL, null, br, mHandler, 0, null, null);

    final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
    synchronized (mActionDoneSync) {
      while (!mActionDone) {
        long delay = endTime - SystemClock.elapsedRealtime();
        if (delay <= 0) {
          Log.w(TAG, "Shutdown broadcast timed out");
          break;
        }
        try {
          mActionDoneSync.wait(delay);
        } catch (InterruptedException e) {
        }
      }
    }

    Log.i(TAG, "Shutting down activity manager...");

    final IActivityManager am =
        ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
    if (am != null) {
      try {
        am.shutdown(MAX_BROADCAST_TIME);
      } catch (RemoteException e) {
      }
    }

    // Shutdown radios.
    shutdownRadios(MAX_RADIO_WAIT_TIME);

    // Shutdown MountService to ensure media is in a safe state
    IMountShutdownObserver observer =
        new IMountShutdownObserver.Stub() {
          public void onShutDownComplete(int statusCode) throws RemoteException {
            Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
            actionDone();
          }
        };

    Log.i(TAG, "Shutting down MountService");

    // Set initial variables and time out time.
    mActionDone = false;
    final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
    synchronized (mActionDoneSync) {
      try {
        final IMountService mount =
            IMountService.Stub.asInterface(ServiceManager.checkService("mount"));
        if (mount != null) {
          mount.shutdown(observer);
        } else {
          Log.w(TAG, "MountService unavailable for shutdown");
        }
      } catch (Exception e) {
        Log.e(TAG, "Exception during MountService shutdown", e);
      }
      while (!mActionDone) {
        long delay = endShutTime - SystemClock.elapsedRealtime();
        if (delay <= 0) {
          Log.w(TAG, "Shutdown wait timed out");
          break;
        }
        try {
          mActionDoneSync.wait(delay);
        } catch (InterruptedException e) {
        }
      }
    }

    rebootOrShutdown(mReboot, mRebootReason);
  }
  /**
   * Makes sure we handle the shutdown gracefully. Shuts off power regardless of radio and bluetooth
   * state if the alloted time has passed.
   */
  public void run() {
    boolean bluetoothOff;
    boolean radioOff;

    BroadcastReceiver br =
        new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
            // We don't allow apps to cancel this, so ignore the result.
            broadcastDone();
          }
        };

    Log.i(TAG, "Sending shutdown broadcast...");

    // First send the high-level shut down broadcast.
    mBroadcastDone = false;
    mContext.sendOrderedBroadcast(
        new Intent(Intent.ACTION_SHUTDOWN), null, br, mHandler, 0, null, null);

    final long endTime = System.currentTimeMillis() + MAX_BROADCAST_TIME;
    synchronized (mBroadcastDoneSync) {
      while (!mBroadcastDone) {
        long delay = endTime - System.currentTimeMillis();
        if (delay <= 0) {
          Log.w(TAG, "Shutdown broadcast timed out");
          break;
        }
        try {
          mBroadcastDoneSync.wait(delay);
        } catch (InterruptedException e) {
        }
      }
    }

    Log.i(TAG, "Shutting down activity manager...");

    final IActivityManager am =
        ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
    if (am != null) {
      try {
        am.shutdown(MAX_BROADCAST_TIME);
      } catch (RemoteException e) {
      }
    }

    final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
    final IBluetooth bluetooth =
        IBluetooth.Stub.asInterface(
            ServiceManager.checkService(BluetoothAdapter.BLUETOOTH_SERVICE));

    final IMountService mount =
        IMountService.Stub.asInterface(ServiceManager.checkService("mount"));

    try {
      bluetoothOff =
          bluetooth == null || bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
      if (!bluetoothOff) {
        Log.w(TAG, "Disabling Bluetooth...");
        bluetooth.disable(false); // disable but don't persist new state
      }
    } catch (RemoteException ex) {
      Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
      bluetoothOff = true;
    }

    try {
      radioOff = phone == null || !phone.isRadioOn();
      if (!radioOff) {
        Log.w(TAG, "Turning off radio...");
        phone.setRadio(false);
      }
    } catch (RemoteException ex) {
      Log.e(TAG, "RemoteException during radio shutdown", ex);
      radioOff = true;
    }

    Log.i(TAG, "Waiting for Bluetooth and Radio...");

    // Wait a max of 32 seconds for clean shutdown
    for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++) {
      if (!bluetoothOff) {
        try {
          bluetoothOff = bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
        } catch (RemoteException ex) {
          Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
          bluetoothOff = true;
        }
      }
      if (!radioOff) {
        try {
          radioOff = !phone.isRadioOn();
        } catch (RemoteException ex) {
          Log.e(TAG, "RemoteException during radio shutdown", ex);
          radioOff = true;
        }
      }
      if (radioOff && bluetoothOff) {
        Log.i(TAG, "Radio and Bluetooth shutdown complete.");
        break;
      }
      SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
    }

    // Shutdown MountService to ensure media is in a safe state
    try {
      if (mount != null) {
        mount.shutdown();
      } else {
        Log.w(TAG, "MountService unavailable for shutdown");
      }
    } catch (Exception e) {
      Log.e(TAG, "Exception during MountService shutdown", e);
    }

    // shutdown power
    Log.i(TAG, "Performing low-level shutdown...");
    Power.shutdown();
  }