Android ShutdownThread.java源码分析

    // constants

    private static final String TAG = “ShutdownThread”;   // Logcat

    private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;

    // maximum time we wait for the shutdown broadcast before going on.

    private static final int MAX_BROADCAST_TIME = 10*1000; // set timeout

    private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;

    private static final int MAX_RADIO_WAIT_TIME = 12*1000;

    // length of vibration before shutting down

    private static final int SHUTDOWN_VIBRATE_MS = 500;

    // state tracking

    private static Object sIsStartedGuard = new Object();

    private static boolean sIsStarted = false;

    private static boolean mReboot;

    private static boolean mRebootSafeMode;

    private static String mRebootReason;

    // Provides shutdown assurance in case the system_server is killed

    public static final String SHUTDOWN_ACTION_PROPERTY = “sys.shutdown.requested”;

    // Indicates whether we are rebooting into safe mode

    public static final String REBOOT_SAFEMODE_PROPERTY = “persist.sys.safemode”;

    // static instance of this thread

    private static final ShutdownThread sInstance = new ShutdownThread();

    private ShutdownThread() {

    }

    private final Object mActionDoneSync = new Object(); //同步对象

    private boolean mActionDone;

    private Context mContext;

    private PowerManager mPowerManager;

    private PowerManager.WakeLock mCpuWakeLock;

    private PowerManager.WakeLock mScreenWakeLock;

    private Handler mHandler;

    private PppoeManager mPppoeManager;

    private static AlertDialog sConfirmDialog;

调用流程

外部调用shutdown,reboot,rebootSafeMode

–>shutdownInner

–>beginShutdownSequence

–>run

–>rebootOrShutdown

–>PowerManagerService.lowLevelShutdown | PowerManagerService.lowLevelReboot

–>(jni)nativeReboot | (jni)nativeShutdown

–>android_reboot(ANDROID_RB_POWEROFF | ANDROID_RB_RESTART | ANDROID_RB_RESTART2,0,(char*)reason)

–>后面就是调用linux的系统调用了,这里就不跟了。。。

    public static void shutdown(final Context context, boolean confirm) {

        mReboot = false;

        mRebootSafeMode = false;

        shutdownInner(context, confirm);

    }

    public static void reboot(final Context context, String reason, boolean confirm) {

        mReboot = true;

        mRebootSafeMode = false;

        mRebootReason = reason;

        shutdownInner(context, confirm);

    }

    public static void rebootSafeMode(final Context context, boolean confirm) {

        mReboot = true;

        mRebootSafeMode = true;

        mRebootReason = null;

        shutdownInner(context, confirm);

    }

    static void shutdownInner(final Context context, boolean confirm) {

        // ensure that only one thread is trying to power down.

        // any additional calls are just returned

        synchronized (sIsStartedGuard) {

            if (sIsStarted) {

                Log.d(TAG, “Request to shutdown already running, returning.”);

                return;

            }

        }

        final int longPressBehavior = context.getResources().getInteger(

                        com.android.internal.R.integer.config_longPressOnPowerBehavior);//1

        final int resourceId = mRebootSafeMode

                ? com.android.internal.R.string.reboot_safemode_confirm

                : (longPressBehavior == 2

                        ? com.android.internal.R.string.shutdown_confirm_question

                        : com.android.internal.R.string.shutdown_confirm);

        Log.d(TAG, “Notifying thread to start shutdown longPressBehavior=” + longPressBehavior);

        if (confirm) {

            final CloseDialogReceiver closer = new CloseDialogReceiver(context);

            if (sConfirmDialog != null) {

                sConfirmDialog.dismiss();

            }

            sConfirmDialog = new AlertDialog.Builder(context)

                    .setTitle(mRebootSafeMode

                            ? com.android.internal.R.string.reboot_safemode_title

                            : com.android.internal.R.string.power_off)

                    .setMessage(resourceId)

                    .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {

                        public void onClick(DialogInterface dialog, int which) {

                            beginShutdownSequence(context);

                        }

                    })

                    .setNegativeButton(com.android.internal.R.string.no, null)

                    .create();

            closer.dialog = sConfirmDialog;

            sConfirmDialog.setOnDismissListener(closer);

            sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);

            sConfirmDialog.show();

        } else {

            beginShutdownSequence(context);

        }

    }

/*  CloseDialogReceiver

    private static class CloseDialogReceiver extends BroadcastReceiver

            implements DialogInterface.OnDismissListener {

        private Context mContext;

        public Dialog dialog;

        CloseDialogReceiver(Context context) {

            mContext = context;

            IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);

            context.registerReceiver(this, filter);

        }

        @Override

        public void onReceive(Context context, Intent intent) {

            dialog.cancel();

        }

        public void onDismiss(DialogInterface unused) {

            mContext.unregisterReceiver(this);

        }

    }

*/

    private static void beginShutdownSequence(Context context) {

        synchronized (sIsStartedGuard) {

            if (sIsStarted) {

                Log.d(TAG, “Shutdown sequence already running, returning.”);

                return;

            }

            sIsStarted = true;

        }

        sInstance.mContext = context;

        sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);

        // make sure we never fall asleep again

        sInstance.mCpuWakeLock = null;

        try {

            sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(

                    PowerManager.PARTIAL_WAKE_LOCK, TAG + “-cpu”);

            sInstance.mCpuWakeLock.setReferenceCounted(false);

            sInstance.mCpuWakeLock.acquire();

        } catch (SecurityException e) {

            Log.w(TAG, “No permission to acquire wake lock”, e);

            sInstance.mCpuWakeLock = null;

        }

        // also make sure the screen stays on for better user experience

        sInstance.mScreenWakeLock = null;

        if (sInstance.mPowerManager.isScreenOn()) {

            try {

                sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(

                        PowerManager.FULL_WAKE_LOCK, TAG + “-screen”);

                sInstance.mScreenWakeLock.setReferenceCounted(false);

                sInstance.mScreenWakeLock.acquire();

            } catch (SecurityException e) {

                Log.w(TAG, “No permission to acquire wake lock”, e);

                sInstance.mScreenWakeLock = null;

            }

        }

        // start the thread that initiates shutdown

        sInstance.mHandler = new Handler() {

        };

        sInstance.start();

    }

    public void run() {

        /*

         * 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);

        }

        //disconnect pppoe before shutting down the system

        mPppoeManager = (PppoeManager) mContext.getSystemService(Context.PPPOE_SERVICE);

        if(-1 != NetworkUtils.checkInterfaceStatus(“ppp0”)) {

            Log.i(TAG,”Pppoe is on, disconnect pppoe”);

            mPppoeManager.setPppoeState(PppoeManager.PPPOE_STATE_DISABLED);

        }

        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();

            }

        };

/*

    void actionDone() {

        synchronized (mActionDoneSync) {

            mActionDone = true;  // 关机重启线程已经启动

            mActionDoneSync.notifyAll();

        }

    }

*/

        /*

         * 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);

    }

    public static void rebootOrShutdown(boolean reboot, String reason) {

        if (reboot) {

            Log.i(TAG, “Rebooting, reason: ” + reason);

            try {

                PowerManagerService.lowLevelReboot(reason);

            } catch (Exception e) {

                Log.e(TAG, “Reboot failed, will attempt shutdown instead”, e);

            }

        } else if (SHUTDOWN_VIBRATE_MS > 0) {

            // vibrate before shutting down

            Vibrator vibrator = new SystemVibrator();

            try {

                vibrator.vibrate(SHUTDOWN_VIBRATE_MS);

            } catch (Exception e) {

                // Failure to vibrate shouldn’t interrupt shutdown.  Just log it.

                Log.w(TAG, “Failed to vibrate during shutdown.”, e);

            }

            // vibrator is asynchronous so we need to wait to avoid shutting down too soon.

            try {

                Thread.sleep(SHUTDOWN_VIBRATE_MS);

            } catch (InterruptedException unused) {

            }

        }

        // Shutdown power

        Log.i(TAG, “Performing low-level shutdown…”);

        PowerManagerService.lowLevelShutdown();

    }

/*shutdownRadios

    private void shutdownRadios(int timeout) {

        // If a radio is wedged, disabling it may hang so we do this work in another thread,

        // just in case.

        final long endTime = SystemClock.elapsedRealtime() + timeout;

        final boolean[] done = new boolean[1];

        Thread t = new Thread() {

            public void run() {

                boolean nfcOff;

                boolean bluetoothOff;

                boolean radioOff;

                final INfcAdapter nfc =

                        INfcAdapter.Stub.asInterface(ServiceManager.checkService(“nfc”));

                final ITelephony phone =

                        ITelephony.Stub.asInterface(ServiceManager.checkService(“phone”));

                final IBluetooth bluetooth =

                        IBluetooth.Stub.asInterface(ServiceManager.checkService(

                                BluetoothAdapter.BLUETOOTH_SERVICE));

                try {

                    nfcOff = nfc == null ||

                             nfc.getState() == NfcAdapter.STATE_OFF;

                    if (!nfcOff) {

                        Log.w(TAG, “Turning off NFC…”);

                        nfc.disable(false); // Don’t persist new state

                    }

                } catch (RemoteException ex) {

                Log.e(TAG, “RemoteException during NFC shutdown”, ex);

                    nfcOff = true;

                }

                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 NFC, Bluetooth and Radio…”);

                while (SystemClock.elapsedRealtime() < endTime) {

                    if (!bluetoothOff) {

                        try {

                            bluetoothOff =

                                    bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;

                        } catch (RemoteException ex) {

                            Log.e(TAG, “RemoteException during bluetooth shutdown”, ex);

                            bluetoothOff = true;

                        }

                        if (bluetoothOff) {

                            Log.i(TAG, “Bluetooth turned off.”);

                        }

                    }

                    if (!radioOff) {

                        try {

                            radioOff = !phone.isRadioOn();

                        } catch (RemoteException ex) {

                            Log.e(TAG, “RemoteException during radio shutdown”, ex);

                            radioOff = true;

                        }

                        if (radioOff) {

                            Log.i(TAG, “Radio turned off.”);

                        }

                    }

                    if (!nfcOff) {

                        try {

                            nfcOff = nfc.getState() == NfcAdapter.STATE_OFF;

                        } catch (RemoteException ex) {

                            Log.e(TAG, “RemoteException during NFC shutdown”, ex);

                            nfcOff = true;

                        }

                        if (radioOff) {

                            Log.i(TAG, “NFC turned off.”);

                        }

                    }

                    if (radioOff && bluetoothOff && nfcOff) {

                        Log.i(TAG, “NFC, Radio and Bluetooth shutdown complete.”);

                        done[0] = true;

                        break;

                    }

                    SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);

                }

            }

        };

        t.start();

        try {

            t.join(timeout);

        } catch (InterruptedException ex) {

        }

        if (!done[0]) {

            Log.w(TAG, “Timed out waiting for NFC, Radio and Bluetooth shutdown.”);

        }

    }

*/

    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/shentong1/article/details/25899887
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞