Android 9.0 關機流程分析

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

#####閱讀五分鐘,每日十點,和您一塊兒終身學習,這裏是程序員Androidandroid

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

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.javaapp

####ShutdownThread 大體流程less

關機線程大體流程

####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方法,實現 彈出 關機 、重啓對話框,供用戶選擇關機 或者重啓。async

/**
     * 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 方法實現ide

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,領福利

相關文章
相關標籤/搜索