Android 9.0 關機流程分析


極力推薦文章:歡迎收藏
Android 干貨分享

閱讀五分鍾,每日十點,和您一起終身學習,這里是程序員Android

本篇文章主要介紹 Android 開發中的部分知識點,通過閱讀本篇文章,您將收獲以下內容:

1.ShutdownThread 概述
2.shutdown 關機方法
3.shutdownInner 方法實現
4.CloseDialogReceiver 注冊關機對話框廣播
5.new sConfirmDialog 顯示關機對話框
6.beginShutdownSequence開始關機流程
7.showShutdownDialog 顯示關機進度對話框
8.判斷是否顯示SystemUIReboot
9.啟動 關機線程 ,執行 Run 方法
10.shutdownRadios 關閉Radio 實現
11.rebootOrShutdown 初始化並決定關機還是重啟
12.關機log 分析

1.ShutdownThread 概述

關機線程實現類

Android 關機線程實現類frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

ShutdownThread 大致流程

關機線程大致流程

ShutdownThread 部分靜態變量如下:

public final class ShutdownThread extends Thread {
    // constants
    private static final String TAG = "ShutdownThread";
    private static final int ACTION_DONE_POLL_WAIT_MS = 500;
    private static final int RADIOS_STATE_POLL_SLEEP_MS = 100;
    // maximum time we wait for the shutdown broadcast before going on.
    private static final int MAX_BROADCAST_TIME = 10*1000;
    private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
    private static final int MAX_RADIO_WAIT_TIME = 12*1000;
    private static final int MAX_UNCRYPT_WAIT_TIME = 15*60*1000;
    // constants for progress bar. the values are roughly estimated based on timeout.
    private static final int BROADCAST_STOP_PERCENT = 2;
    private static final int ACTIVITY_MANAGER_STOP_PERCENT = 4;
    private static final int PACKAGE_MANAGER_STOP_PERCENT = 6;
    private static final int RADIO_STOP_PERCENT = 18;
    private static final int MOUNT_SERVICE_STOP_PERCENT = 20;
    // Time we should wait for vendor subsystem shutdown
    // Sleep times(ms) between checks of the vendor subsystem state
    private static final int VENDOR_SUBSYS_STATE_CHECK_INTERVAL_MS = 100;
    // Max time we wait for vendor subsystems to shut down before resuming
    // with full system shutdown
    private static final int VENDOR_SUBSYS_MAX_WAIT_MS = 10000;

    // length of vibration before shutting down
    private static final int SHUTDOWN_VIBRATE_MS = 500;

    ... ...
}

ShutdownThread 無參構造方法

  private ShutdownThread() {
    }

2. shutdown 關機方法

長按 ·Power· 鍵調用 shutdown 方法,通過調用內部shutdownInner方法,實現 彈出 關機 、重啟對話框,供用戶選擇關機 或者重啟。

 /**
     * Request a clean shutdown, waiting for subsystems to clean up their
     * state etc.  Must be called from a Looper thread in which its UI
     * is shown.
     *
     * @param context Context used to display the shutdown progress dialog. This must be a context
     *                suitable for displaying UI (aka Themable).
     * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
     * @param confirm true if user confirmation is needed before shutting down.
     */
    public static void shutdown(final Context context, String reason, boolean confirm) {
        mReboot = false;
        mRebootSafeMode = false;
        mReason = reason;
        shutdownInner(context, confirm); // 詳見分析3
    }

3.shutdownInner 方法實現

shutdownInner 主要作用是
1.獲取用戶關機 Behavior
2.注冊關機廣播,詳見4.
3.創建關機Dialog
4.執行一系列關機流程。

   private static void shutdownInner(final Context context, boolean confirm) {
        // ShutdownThread is called from many places, so best to verify here that the context passed
        // in is themed.
        context.assertRuntimeOverlayThemable();

        // 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;
            }
        }
        // 獲取用戶長按Power鍵的處理行為
        final int longPressBehavior = context.getResources().getInteger(
                        com.android.internal.R.integer.config_longPressOnPowerBehavior);
        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) {
           //注冊關機對話框廣播  詳細實現見 4
            final CloseDialogReceiver closer = new CloseDialogReceiver(context);
            if (sConfirmDialog != null) {
                sConfirmDialog.dismiss();
            }
            // 創建關機Dialg 詳見 實現5
            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) {
                             // 開始一系列的關機流程,詳見 6
                            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);
        }
    }

其中 config_longPressOnPowerBehavior 用來控制用戶長按Power鍵觸發的行為。
主要行為如下:

 <!-- Control the behavior when the user long presses the power button.
            0 - Nothing
            1 - Global actions menu
            2 - Power off (with confirmation)
            3 - Power off (without confirmation)
            4 - Go to voice assist
    -->
    <integer name="config_longPressOnPowerBehavior">1</integer>

此源碼 可以在 config.xml中查看,代碼目錄如下:frameworks\base\core\res\res\values\config.xml

4.CloseDialogReceiver 注冊關機對話框廣播

注冊actionACTION_CLOSE_SYSTEM_DIALOGS廣播接收器。

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

5. new sConfirmDialog 顯示關機對話框

Android 原生關機對話框如下:
關機對話框創建

            // 創建關機Dialg 詳見 實現5
            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) {
                             // 開始一系列的關機流程,詳見 6
                            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();

6. beginShutdownSequence開始關機流程

beginShutdownSequence 開始一系列關機流程,主要功能如下:
1.顯示關機進度條對話框。
2.啟動ShutdownThead 線程。


    private static void beginShutdownSequence(Context context) {
        synchronized (sIsStartedGuard) {
            if (sIsStarted) {
                Log.d(TAG, "Shutdown sequence already running, returning.");
                return;
            }
            sIsStarted = true;
        }
        // 顯示關機進度對話框 詳見 7 
        sInstance.mProgressDialog = showShutdownDialog(context);
        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;
            }
        }

        if (SecurityLog.isLoggingEnabled()) {
            SecurityLog.writeEvent(SecurityLog.TAG_OS_SHUTDOWN);
        }

        // 啟動 關機線程 ,執行 Run 方法,詳見 9
        sInstance.mHandler = new Handler() {
        };
        sInstance.start();
    }

7.showShutdownDialog 顯示關機進度對話框

showShutdownDialog 主要用來顯示關機進度對話框


    private static ProgressDialog showShutdownDialog(Context context) {
        // Throw up a system dialog to indicate the device is rebooting / shutting down.
        ProgressDialog pd = new ProgressDialog(context);

        // Path 1: Reboot to recovery for update
        //   Condition: mReason startswith REBOOT_RECOVERY_UPDATE
        //
        //  Path 1a: uncrypt needed
        //   Condition: if /cache/recovery/uncrypt_file exists but
        //              /cache/recovery/block.map doesn't.
        //   UI: determinate progress bar (mRebootHasProgressBar == True)
        //
        // * Path 1a is expected to be removed once the GmsCore shipped on
        //   device always calls uncrypt prior to reboot.
        //
        //  Path 1b: uncrypt already done
        //   UI: spinning circle only (no progress bar)
        //
        // Path 2: Reboot to recovery for factory reset
        //   Condition: mReason == REBOOT_RECOVERY
        //   UI: spinning circle only (no progress bar)
        //
        // Path 3: Regular reboot / shutdown
        //   Condition: Otherwise
        //   UI: spinning circle only (no progress bar)

        // mReason could be "recovery-update" or "recovery-update,quiescent".
        if (mReason != null && mReason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
            // We need the progress bar if uncrypt will be invoked during the
            // reboot, which might be time-consuming.
            mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists()
                    && !(RecoverySystem.BLOCK_MAP_FILE.exists());
            pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
            if (mRebootHasProgressBar) {
                pd.setMax(100);
                pd.setProgress(0);
                pd.setIndeterminate(false);
                pd.setProgressNumberFormat(null);
                pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                pd.setMessage(context.getText(
                            com.android.internal.R.string.reboot_to_update_prepare));
            } else {
                if (showSysuiReboot()) {
                    return null;
                }
                pd.setIndeterminate(true);
                pd.setMessage(context.getText(
                            com.android.internal.R.string.reboot_to_update_reboot));
            }
        } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
            if (RescueParty.isAttemptingFactoryReset()) {
                // We're not actually doing a factory reset yet; we're rebooting
                // to ask the user if they'd like to reset, so give them a less
                // scary dialog message.
                pd.setTitle(context.getText(com.android.internal.R.string.power_off));
                pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
                pd.setIndeterminate(true);
            } else {
                // Factory reset path. Set the dialog message accordingly.
                pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
                pd.setMessage(context.getText(
                            com.android.internal.R.string.reboot_to_reset_message));
                pd.setIndeterminate(true);
            }
        } else {
           // 判斷是否顯示SystemUIReboot 詳見 8
            if (showSysuiReboot()) {
                return null;
            }
            // 顯示關機 進度對話框 詳見 8
            pd.setTitle(context.getText(com.android.internal.R.string.power_off));
            pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
            pd.setIndeterminate(true);
        }
        pd.setCancelable(false);
        pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);

        pd.show();
        return pd;
    }

關機 進度對話框實現

關機 進度對話框實現

8.判斷是否顯示SystemUIReboot

showSysuiReboot 主要用來顯示是否顯示SystemUIReboot.


    private static boolean showSysuiReboot() {
        Log.d(TAG, "Attempting to use SysUI shutdown UI");
        try {
            StatusBarManagerInternal service = LocalServices.getService(
                    StatusBarManagerInternal.class);
            if (service.showShutdownUi(mReboot, mReason)) {
                // Sysui will handle shutdown UI.
                Log.d(TAG, "SysUI handling shutdown UI");
                return true;
            }
        } catch (Exception e) {
            // If anything went wrong, ignore it and use fallback ui
        }
        Log.d(TAG, "SysUI is unavailable");
        return false;
    }

9.啟動 關機線程 ,執行 Run 方法

beginShutdownSequence方法中啟動 關機線程。

    private static void beginShutdownSequence(Context context) {
      ... ...
    // static instance of this thread
    private static final ShutdownThread sInstance = new ShutdownThread();
        // start the thread that initiates shutdown
        sInstance.mHandler = new Handler() {
        };
        sInstance.start();
        ... ...
}
ShutdownThread Run 實現

ShutdownThread 主要作用:
1.發送有序的關機廣播。
2.測量關閉某些項目的時間。
3.關閉 ActivityManager
4.關閉PackageManager
5.關閉 Radios
6.完成System Server 的關閉。
7.初始化並判定執行關機還是重啟


    /**
     * Makes sure we handle the shutdown gracefully.
     * Shuts off power regardless of radio state if the allotted time has passed.
     */
    public void run() {
        TimingsTraceLog shutdownTimingLog = newTimingsLog();
        shutdownTimingLog.traceBegin("SystemServerShutdown");
        metricShutdownStart();
        metricStarted(METRIC_SYSTEM_SERVER);

        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") + (mReason != null ? mReason : "");
            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");
        }

        metricStarted(METRIC_SEND_BROADCAST);
        shutdownTimingLog.traceBegin("SendShutdownBroadcast");
	
        Log.i(TAG, "Sending shutdown broadcast...");

        // First send the high-level shut down broadcast.
        mActionDone = false;
        Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
		// 發送 有序的 關機廣播
        mContext.sendOrderedBroadcastAsUser(intent,
                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;
                } else if (mRebootHasProgressBar) {
                    int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
                            BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
                    sInstance.setRebootProgress(status, null);
                }
                try {
                    mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
                } catch (InterruptedException e) {
                }
            }
        }
        if (mRebootHasProgressBar) {
            sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
        }
		//  測量 發送有序 關機廣播所用的時間
        shutdownTimingLog.traceEnd(); // SendShutdownBroadcast
        metricEnded(METRIC_SEND_BROADCAST);

        Log.i(TAG, "Shutting down activity manager...");
        shutdownTimingLog.traceBegin("ShutdownActivityManager");
        metricStarted(METRIC_AM);
        // 關閉 Activity Manager
        final IActivityManager am =
                IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
        if (am != null) {
            try {
                am.shutdown(MAX_BROADCAST_TIME);
            } catch (RemoteException e) {
            }
        }
        if (mRebootHasProgressBar) {
            sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
        }
        shutdownTimingLog.traceEnd();// ShutdownActivityManager
        metricEnded(METRIC_AM);

        Log.i(TAG, "Shutting down package manager...");
        shutdownTimingLog.traceBegin("ShutdownPackageManager");
        metricStarted(METRIC_PM);
        // 關閉 Package Manager
        final PackageManagerService pm = (PackageManagerService)
            ServiceManager.getService("package");
        if (pm != null) {
            pm.shutdown();
        }
        if (mRebootHasProgressBar) {
            sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
        }
        shutdownTimingLog.traceEnd(); // ShutdownPackageManager
        metricEnded(METRIC_PM);

        // Shutdown radios.
        shutdownTimingLog.traceBegin("ShutdownRadios");
        metricStarted(METRIC_RADIOS);
		//關閉  Radios  shutdownRadios 詳細 請看 10
        shutdownRadios(MAX_RADIO_WAIT_TIME);
        if (mRebootHasProgressBar) {
            sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
        }
        shutdownTimingLog.traceEnd(); // ShutdownRadios
        metricEnded(METRIC_RADIOS);

        //  關閉 System Server 
        if (mRebootHasProgressBar) {
            sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);

            // If it's to reboot to install an update and uncrypt hasn't been
            // done yet, trigger it now.
            uncrypt();
        }

        shutdownTimingLog.traceEnd(); // SystemServerShutdown
        metricEnded(METRIC_SYSTEM_SERVER);
        saveMetrics(mReboot, mReason);
        //初始化 並判斷是關機還是重啟 詳見 11
        rebootOrShutdown(mContext, mReboot, mReason);
    }

10.shutdownRadios 關閉Radio 實現

shutdownRadios 用來關閉phone Radio相關內容 ,主要實現如下:


    private void shutdownRadios(final 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];
		//另起線程 異步關閉 Radios
        Thread t = new Thread() {
            public void run() {
                TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
                boolean radioOff;

                final ITelephony phone =
                        ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));

                try {
                    radioOff = phone == null || !phone.needMobileRadioShutdown();
                    if (!radioOff) {
                        Log.w(TAG, "Turning off cellular radios...");
                        metricStarted(METRIC_RADIO);
                        phone.shutdownMobileRadios();
                    }
                } catch (RemoteException ex) {
                    Log.e(TAG, "RemoteException during radio shutdown", ex);
                    radioOff = true;
                }
                
                Log.i(TAG, "Waiting for Radio...");

                long delay = endTime - SystemClock.elapsedRealtime();
                while (delay > 0) {
                    if (mRebootHasProgressBar) {
                        int status = (int)((timeout - delay) * 1.0 *
                                (RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout);
                        status += PACKAGE_MANAGER_STOP_PERCENT;
                        sInstance.setRebootProgress(status, null);
                    }

                    if (!radioOff) {
                        try {
                            radioOff = !phone.needMobileRadioShutdown();
                        } catch (RemoteException ex) {
                            Log.e(TAG, "RemoteException during radio shutdown", ex);
                            radioOff = true;
                        }
                        if (radioOff) {
                            Log.i(TAG, "Radio turned off.");
                            metricEnded(METRIC_RADIO);
                            shutdownTimingsTraceLog
                                    .logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO));
                        }
                    }

                    if (radioOff) {
                        Log.i(TAG, "Radio shutdown complete.");
                        done[0] = true;
                        break;
                    }
                    SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS);
                    delay = endTime - SystemClock.elapsedRealtime();
                }
            }
        };
        //另起線程 異步關閉 Radios
        t.start();
        try {
            t.join(timeout);
        } catch (InterruptedException ex) {
        }
        if (!done[0]) {
            Log.w(TAG, "Timed out waiting for Radio shutdown.");
        }
    }

11.rebootOrShutdown 初始化並決定關機還是重啟

rebootOrShutdown主要用來 初始化並決定關機還是重啟。



    /**
     * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
     * or {@link #shutdown(Context, String, boolean)} instead.
     *
     * @param context Context used to vibrate or null without vibration
     * @param reboot true to reboot or false to shutdown
     * @param reason reason for reboot/shutdown
     */
    public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
        String subsysProp;
        subsysProp = SystemProperties.get("vendor.peripheral.shutdown_critical_list",
                        "ERROR");
        //If we don't have the shutdown critical subsystem list we can't
        //really do anything. Proceed with full system shutdown.
        if (!subsysProp.equals("ERROR")) {
                Log.i(TAG, "Shutdown critical subsyslist is :"+subsysProp+": ");
                Log.i(TAG, "Waiting for a maximum of " +
                           (VENDOR_SUBSYS_MAX_WAIT_MS) + "ms");
                String[] subsysList = subsysProp.split(" ");
                int wait_count = 0;
                boolean okToShutdown = true;
                String subsysState;
                int subsysListLength = subsysList.length;
                do {
                        okToShutdown = true;
                        for (int i = 0; i < subsysListLength; i++) {
                                subsysState =
                                        SystemProperties.get(
                                                        "vendor.peripheral." +
                                                        subsysList[i] +
                                                        ".state",
                                                        "ERROR");
                                if(subsysState.equals("ONLINE"))  {
                                        //We only want to delay shutdown while
                                        //one of the shutdown critical
                                        //subsystems still shows as 'ONLINE'.
                                        okToShutdown = false;
                                }
                        }
                        if (okToShutdown == false) {
                                SystemClock.sleep(VENDOR_SUBSYS_STATE_CHECK_INTERVAL_MS);
                                wait_count++;
                        }
                } while (okToShutdown != true &&
                                wait_count < (VENDOR_SUBSYS_MAX_WAIT_MS/VENDOR_SUBSYS_STATE_CHECK_INTERVAL_MS));
                if (okToShutdown != true) {
                        for (int i = 0; i < subsysList.length; i++) {
                                subsysState =
                                        SystemProperties.get(
                                                        "vendor.peripheral." +
                                                        subsysList[i] +
                                                        ".state",
                                                        "ERROR");
                                if(subsysState.equals("ONLINE"))  {
                                        Log.w(TAG, "Subsystem " + subsysList[i]+
                                                   "did not shut down within timeout");
                                }
                        }
                } else {
                        Log.i(TAG, "Vendor subsystem(s) shutdown successful");
                }
        }
        if (reboot) {
            Log.i(TAG, "Rebooting, reason: " + reason);
            PowerManagerService.lowLevelReboot(reason);
            Log.e(TAG, "Reboot failed, will attempt shutdown instead");
            reason = null;
        } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
            // vibrate before shutting down
            Vibrator vibrator = new SystemVibrator(context);
            try {
                vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
            } 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(reason);
    }

12. 關機log 分析

通過 鏈接adb,我們可以抓取關機的Log, 部分Log信息如下:

Line 96: 07-26 01:02:26.205  2510  3766 I AudioController: internalShutdown
	Line 540: 07-26 01:02:30.968   790   790 D ShutdownThread: Notifying thread to start shutdown longPressBehavior=1
	Line 540: 07-26 01:02:30.968   790   790 D ShutdownThread: Notifying thread to start shutdown longPressBehavior=1
	Line 541: 07-26 01:02:30.970   790   790 D ShutdownThread: Attempting to use SysUI shutdown UI
	Line 541: 07-26 01:02:30.970   790   790 D ShutdownThread: Attempting to use SysUI shutdown UI
	Line 542: 07-26 01:02:30.971   790   790 D ShutdownThread: SysUI handling shutdown UI
	Line 542: 07-26 01:02:30.971   790   790 D ShutdownThread: SysUI handling shutdown UI
	Line 555: 07-26 01:02:30.997   790  3902 I ShutdownThread: Sending shutdown broadcast...
	Line 555: 07-26 01:02:30.997   790  3902 I ShutdownThread: Sending shutdown broadcast...
	Line 561: 07-26 01:02:31.014   790   790 W SyncManager: Writing sync state before shutdown...
	Line 666: 07-26 01:02:31.436  2510  3766 I AudioController: internalShutdown
	Line 669: 07-26 01:02:31.443   790   790 I StatsCompanionService: StatsCompanionService noticed a shutdown.
	Line 708: 07-26 01:02:31.671   790  3902 D ShutdownTiming: SendShutdownBroadcast took to complete: 675ms
	Line 708: 07-26 01:02:31.671   790  3902 D ShutdownTiming: SendShutdownBroadcast took to complete: 675ms
	Line 711: 07-26 01:02:31.671   790  3902 I ShutdownThread: Shutting down activity manager...
	Line 740: 07-26 01:02:31.954   790  3902 W AppOps  : Writing app ops before shutdown...
	Line 771: 07-26 01:02:32.152   790  3902 W BatteryStats: Writing battery stats before shutdown...
	Line 806: 07-26 01:02:32.386   790  1015 W system_server: Long monitor contention with owner Thread-29 (3902) at void com.android.server.am.BatteryStatsService.shutdown()(BatteryStatsService.java:249) waiters=0 in void com.android.server.am.BatteryStatsService.noteProcessStart(java.lang.String, int) for 132ms
	Line 840: 07-26 01:02:32.507   790  3902 W ProcessStatsService: Writing process stats before shutdown...
	Line 850: 07-26 01:02:32.563   790  3902 D ShutdownTiming: ShutdownActivityManager took to complete: 891ms
	Line 850: 07-26 01:02:32.563   790  3902 D ShutdownTiming: ShutdownActivityManager took to complete: 891ms
	Line 853: 07-26 01:02:32.563   790  3902 I ShutdownThread: Shutting down package manager...
	Line 872: 07-26 01:02:32.656   790  3902 D ShutdownTiming: ShutdownPackageManager took to complete: 93ms
	Line 872: 07-26 01:02:32.656   790  3902 D ShutdownTiming: ShutdownPackageManager took to complete: 93ms
	Line 879: 07-26 01:02:32.677  1804  1976 V PhoneInterfaceManager: [PhoneIntfMgr] 1 Phones are shutdown.
	Line 882: 07-26 01:02:32.678   790  3951 I ShutdownThread: Waiting for Radio...
	Line 883: 07-26 01:02:32.679   790  3951 I ShutdownThread: Radio shutdown complete.
	Line 883: 07-26 01:02:32.679   790  3951 I ShutdownThread: Radio shutdown complete.
	Line 884: 07-26 01:02:32.681   790  3902 D ShutdownTiming: ShutdownRadios took to complete: 25ms
	Line 884: 07-26 01:02:32.681   790  3902 D ShutdownTiming: ShutdownRadios took to complete: 25ms
	Line 885: 07-26 01:02:32.681   790  3902 D ShutdownTiming: SystemServerShutdown took to complete: 1705ms
	Line 885: 07-26 01:02:32.681   790  3902 D ShutdownTiming: SystemServerShutdown took to complete: 1705ms
	Line 886: 07-26 01:02:32.684   790  3902 I ShutdownThread: Shutdown critical subsyslist is :modem : 
	Line 886: 07-26 01:02:32.684   790  3902 I ShutdownThread: Shutdown critical subsyslist is :modem : 
	Line 887: 07-26 01:02:32.684   790  3902 I ShutdownThread: Waiting for a maximum of 10000ms
	Line 888: 07-26 01:02:32.684   790  3902 I ShutdownThread: Vendor subsystem(s) shutdown successful
	Line 888: 07-26 01:02:32.684   790  3902 I ShutdownThread: Vendor subsystem(s) shutdown successful
	Line 931: 07-26 01:02:33.192   790  3902 I ShutdownThread: Performing low-level shutdown...
	Line 931: 07-26 01:02:33.192   790  3902 I ShutdownThread: Performing low-level shutdown...
	Line 1003: 07-26 01:02:33.543   565   585 E Dpps    : ProcessAlMsg():471 Shutdown event recieved quit -108
	Line 1005: 07-26 01:02:33.543   565   585 I Dpps    : ProcessNextEvent():142 Shutdown notification quit processing
	Line 1009: 07-26 01:02:33.562   565   583 E Dpps    : ProcessAbaMsg():579 Shutdown event recieved quit -108

至此,本篇已結束,如有不對的地方,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

微信關注公眾號:  程序員Android,領福利


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM