Android 關機、重啟、recovery流程分析

renke發表於2021-09-09

以Android5.1的程式碼來分析。

上層應用可以透過PowerManager來實現關機、重啟、進recovery等功能。比如RecoverySystem 中就是使用PM使系統進入recovery模式:

原始碼路徑:frameworks/base/core/java/android/os/RecoverySystem.java

    private static void bootCommand(Context context, String... args) throws IOException {        ......
        // Having written the command file, go ahead and reboot
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        pm.reboot(PowerManager.REBOOT_RECOVERY);       ......
    }

PowerManager會透過aidl與PowerManagerService互動,reboot帶reason引數,像重啟、關機、恢復出廠設定等等;

原始碼路徑:frameworks/base/core/java/android/os/IPowerManager.aidl

interface IPowerManager{    // WARNING: The first five methods must remain the first five methods because their
    // transaction numbers must not change unless IPowerManager.cpp is also updated.
    void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws,
            String historyTag);    void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName,            int uidtoblame);    void releaseWakeLock(IBinder lock, int flags);    void updateWakeLockUids(IBinder lock, in int[] uids);
    ......    void reboot(boolean confirm, String reason, boolean wait);    void shutdown(boolean confirm, boolean wait);    void crash(String message);    void setStayOnSetting(int val);    void boostScreenBrightness(long time);    // temporarily overrides the screen brightness settings to allow the user to
    // see the effect of a settings change without applying it immediately
    void setTemporaryScreenBrightnessSettingOverride(int brightness);    void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj);    // sets the attention light (used by phone app only)
    void setAttentionLight(boolean on, int color);
}

原始碼路徑:frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

        @Override // Binder call
        public void reboot(boolean confirm, String reason, boolean wait) {
            ......            final long ident = Binder.clearCallingIdentity();            try {
                shutdownOrRebootInternal(false, confirm, reason, wait);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    public static void lowLevelShutdown() {
        SystemProperties.set("sys.powerctl", "shutdown");
    }
    public static void lowLevelReboot(String reason) {        if (reason == null) {
            reason = "";
        }
        long duration;        if (reason.equals(PowerManager.REBOOT_RECOVERY)) {
            SystemProperties.set("ctl.start", "pre-recovery");            duration = 300 * 1000L;
        } else {
            SystemProperties.set("sys.powerctl", "reboot," + reason);            duration = 20 * 1000L;
        }
        try {            Thread.sleep(duration);
        } catch (InterruptedException e) {            Thread.currentThread().interrupt();
        }
    }

shutdownOrRebootInternal根據reason來決定是呼叫ShutdownThread的reboot或者shutdown:

  private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,            final String reason, boolean wait) {
        ......
        Runnable runnable = new Runnable() {            @Override
            public void run() {                synchronized (this) {                    if (shutdown) {
                        ShutdownThread.shutdown(mContext, confirm);
                    } else {
                        ShutdownThread.reboot(mContext, reason, confirm);
                    }
                ......

不管是關機還是重啟都是走shutdownInner 原始碼路徑:frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

    public static void reboot(final Context context, String reason, boolean confirm) {
        mReboot = true;
        mRebootSafeMode = false;
        mRebootReason = reason;
        shutdownInner(context, confirm);
    }
    ......    public static void shutdown(final Context context, boolean confirm) {
        mReboot = false;
        mRebootSafeMode = false;
        shutdownInner(context, confirm);
    }
    ......    static void shutdownInner(final Context context, boolean confirm) {
    ......
            beginShutdownSequence(context);
        }
    }

看一下beginShutdownSequence

    private static void beginShutdownSequence(Context context) {
       ......        // start the thread that initiates shutdown
        sInstance.mHandler = new Handler() {
        };
        sInstance.start();
    }

已經start了,我們就去run裡面瞧一瞧幹了什麼事,就對“REBOOT_SAFEMODE_PROPERTY”設定了1或者0,然後呼叫rebootOrShutdown。

   /**
     * 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() {        ....//關機或者重啟前的一些處理
            String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);......
        if (mRebootSafeMode) {
            SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
        }        ......
        rebootOrShutdown(mReboot, mRebootReason);
    }

rebootOrShutdown中會呼叫PMS的lowLevelReboot或者lowLevelShutdown,這兩個函式在上面有展示

    public static void rebootOrShutdown(boolean reboot, String reason) {        if (reboot) {            Log.i(TAG, "Rebooting, reason: " + reason);
            PowerManagerService.lowLevelReboot(reason);//重啟
            Log.e(TAG, "Reboot failed, will attempt shutdown instead");
        } else if (SHUTDOWN_VIBRATE_MS > 0) {      ....//關機震動相關處理
        // Shutdown power
        Log.i(TAG, "Performing low-level shutdown...");
        PowerManagerService.lowLevelShutdown();//關機
    }

再回過頭去看PowerManagerService裡面的lowLevelShutdown,發現關機、重啟、recovery等是透過設定Properties來實現控制的:SystemProperties.set("sys.powerctl"......


Android系統開始會執行init,而init會去解析執行init.rc中的內容。其中就有對於Properties “sys.powerctl ”的處理(當“sys.powerctl 發生改變時觸發進行powerctl 操作)。 位於原始碼:system/core/rootdir/init.rc

on property:sys.powerctl=*
    powerctl ${sys.powerctl}

而powerctl 是init的內嵌命令,在init原始碼中: 原始碼路徑:system/core/init/builtins.c

int do_powerctl(int nargs, char **args)
{
......    if (strncmp(command, "shutdown", 8) == 0) {
        cmd = ANDROID_RB_POWEROFF;        len = 8;
    } else if (strncmp(command, "reboot", 6) == 0) {
        cmd = ANDROID_RB_RESTART2;        len = 6;
    } else {
        ERROR("powerctl: unrecognized command '%s'n", command);        return -EINVAL;
    }    if (command[len] == ',') {
        reboot_target = &command[len + 1];
    } else if (command[len] == '

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/430/viewspace-2809611/,如需轉載,請註明出處,否則將追究法律責任。

相關文章