Android 关机流程

Power键灭屏流程是从PhoneWindowManager监听Power键开始的,PowerManager负责调用PMS下的GoToSleep方法灭屏,Notifier负责发灭屏广播,WinDowManagerPolicy负责锁屏,其时序图如

 

以按Power键关机流程为例子分析一下流程:

Power键的key值响应在PhoneWindowManager的interceptKeyBeforeQueueing中接收Keycode值做相应的处理(亮灭屏过程中Power down执行wakeup,up执行goToSleep)

    @Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

...
        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
...
        // Handle special keys.
        switch (keyCode) {
            case KeyEvent.KEYCODE_POWER: {
                // Any activity on the power button stops the accessibility shortcut
                cancelPendingAccessibilityShortcutAction();
                result &= ~ACTION_PASS_TO_USER;
                isWakeKey = false; // wake-up will be handled separately
                if (down) {
                   interceptPowerKeyDown(event, interactive);
                }else{
                    interceptPowerKeyUp(event, interactive, canceled);
                }
...
...
    }

当检测到Power键被down之后,检测screenshot chord,检测有电话铃声会置静音等操作,


    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
        // Hold a wake lock until the power key is released.
        if (!mPowerKeyWakeLock.isHeld()) {
            mPowerKeyWakeLock.acquire();
        }
...
...
        // If the power key has still not yet been handled, then detect short
        // press, long press, or multi press and decide what to do.
        mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
                || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
        if (!mPowerKeyHandled) {
            if (interactive) {
                // When interactive, we're already awake.
                // Wait for a long press or for the button to be released to decide what to do.
                if (hasLongPressOnPowerBehavior()) {
                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageDelayed(msg,
                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                }
            } else {
//唤醒操作
                wakeUpFromPowerKey(event.getDownTime());

                if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {
                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageDelayed(msg,
                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                    mBeganFromNonInteractive = true;
                } else {
                    final int maxCount = getMaxMultiPressPowerCount();

                    if (maxCount <= 1) {
                        mPowerKeyHandled = true;
                    } else {
                        mBeganFromNonInteractive = true;
                    }
                }
            }
        }
    }

根据interactive标志位检测是否处于活跃状态,如果是且检测到是长按Power键行为,则通过Handler发送

 private class PolicyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
...
...
                case MSG_POWER_LONG_PRESS:
                    powerLongPress();
                    break;
....
            }
        }
    }

在powerLongPress中

    private void powerLongPress() {
        final int behavior = getResolvedLongPressOnPowerBehavior();
        switch (behavior) {
        case LONG_PRESS_POWER_NOTHING:
            break;
        case LONG_PRESS_POWER_GLOBAL_ACTIONS://显示系统弹框
            mPowerKeyHandled = true;
            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
            showGlobalActionsInternal();
            break;
        case LONG_PRESS_POWER_SHUT_OFF:
        case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM: //直接关机
            mPowerKeyHandled = true;
            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
            mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
            break;
        }
    }

这LONG_PRESS_POWER_GLOBAL_ACTIONS中performHapticFeedbackLw主要是用来获取震动强度showGlobalActionsInternal用来显示系统关机的Dialog


   void showGlobalActionsInternal() {
        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);//先关闭系统的dialog
        if (mGlobalActions == null) {
            //创建GlobalActions
            mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
        }
        final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
        //showDialog
        mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
        if (keyguardShowing) {
            // since it took two seconds of long press to bring this up,
            // poke the wake lock so they have some time to see the dialog.
            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
        }
    }

在showDialog中

\frameworks\base\packages\SystemUI\plugin\src\com\android\systemui\plugins\GlobalActions.java    
 public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) {
        if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned);
        mKeyguardShowing = keyguardShowing;
        mDeviceProvisioned = deviceProvisioned;
        mShowing = true;
        if (mStatusBarConnected) {
            mStatusBarInternal.showGlobalActions();
            mHandler.postDelayed(mShowTimeout, 5000);
        } else {
            // SysUI isn't alive, show legacy menu.
            ensureLegacyCreated();
            mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
        }
    }

在showGlobalActions中

frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
    @Override
    public void showGlobalActions(GlobalActionsManager manager) {
        if (mGlobalActions == null) {
            //创建GlobalActionsDialog
            mGlobalActions = new GlobalActionsDialog(mContext, manager);
        }
         //显示Dislog
        mGlobalActions.showDialog(mKeyguardMonitor.isShowing(),
                mDeviceProvisionedController.isDeviceProvisioned());
    }

GlobalActionsDialog

/**
 * Helper to show the global actions dialog.  Each item is an {@link Action} that
 * may show depending on whether the keyguard is showing, and whether the device
 * is provisioned.
 */
class GlobalActionsDialog implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
....
....
    public GlobalActionsDialog(Context context, GlobalActionsManager windowManagerFuncs) {
...
...
        // receive broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
        context.registerReceiver(mBroadcastReceiver, filter);
...
...
}
...
...
    /**
     * Show the global actions dialog (creating if necessary)
     *
     * @param keyguardShowing True if keyguard is showing
     */
    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
        mKeyguardShowing = keyguardShowing;
        mDeviceProvisioned = isDeviceProvisioned;
        if (mDialog != null) {
            mDialog.dismiss();
            mDialog = null;
            // Show delayed, so that the dismiss of the previous dialog completes
            mHandler.sendEmptyMessage(MESSAGE_SHOW);
        } else {
            handleShow();
        }
    }
...
...

    private void handleShow() {
        awakenIfNecessary();
        mDialog = createDialog();
        prepareDialog();
        // If we only have 1 item and it's a simple press action, just do this action.
        if (mAdapter.getCount() == 1
                && mAdapter.getItem(0) instanceof SinglePressAction
                && !(mAdapter.getItem(0) instanceof LongPressAction)) {
            ((SinglePressAction) mAdapter.getItem(0)).onPress();
        } else {
            WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
            attrs.setTitle("ActionsDialog");
            mDialog.getWindow().setAttributes(attrs);
            mDialog.show();
            mWindowManagerFuncs.onGlobalActionsShown();
        }
    }
...
...
...
    /**
     * Create the global actions dialog.
     *
     * @return A new dialog.
     */
    private ActionsDialog createDialog() {
....
....        mItems = new ArrayList<Action>();
        String[] defaultActions = mContext.getResources().getStringArray(
                R.array.config_globalActionsList);//获取默认的参数列表
        ArraySet<String> addedKeys = new ArraySet<String>();
        for (int i = 0; i < defaultActions.length; i++) {
            String actionKey = defaultActions[i];
            if (addedKeys.contains(actionKey)) {
                // If we already have added this, don't add it again.
                continue;
            }
            if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
                mItems.add(new PowerAction());// 添加关机模式图标和对应事件
            } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
                mItems.add(mAirplaneModeOn);// 添加飞行模式图标和对应事件
            }
....
....
            else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
                mItems.add(new RestartAction());// 添加重启图标和对应事件
            } 
....
            // Add here so we don't add more than one.
            addedKeys.add(actionKey);
        }
...
...

        ActionsDialog dialog = new ActionsDialog(mContext, this, mAdapter, onItemLongClickListener);
        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
        dialog.setKeyguardShowing(mKeyguardShowing);

        dialog.setOnDismissListener(this);

        return dialog;
}

在关机模式中一个是长按diaog重启操作mWindowManagerFuncs.reboot(true);一个是短按mWindowManagerFuncs.shutdown();关机操作

frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
  
  private final class PowerAction extends SinglePressAction implements LongPressAction {
        private PowerAction() {
            super(R.drawable.ic_lock_power_off,
                    R.string.global_action_power_off);
        }
        @Override
        public boolean onLongPress() {
            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
            if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
                mWindowManagerFuncs.reboot(true);
                return true;
            }
            return false;
        }
        @Override
        public boolean showDuringKeyguard() {
            return true;
        }

        @Override
        public boolean showBeforeProvisioning() {
            return true;
        }
        @Override
        public void onPress() {
            // shutdown by making sure radio and power are handled accordingly.
            mWindowManagerFuncs.shutdown();
        }
    }

另外RestartAction中重启操作

    private final class RestartAction extends SinglePressAction implements LongPressAction {
        private RestartAction() {
            super(R.drawable.ic_restart, R.string.global_action_restart);
        }
        @Override
        public boolean onLongPress() {
            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
            if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
                mWindowManagerFuncs.reboot(true);
                return true;
            }
            return false;
        }
        @Override
        public boolean showDuringKeyguard() {
            return true;
        }

        @Override
        public boolean showBeforeProvisioning() {
            return true;
        }
        @Override
        public void onPress() {
            mWindowManagerFuncs.reboot(false);
        }
    }

其中的mWindowManagerFuncs来自于

 private final GlobalActionsManager mWindowManagerFuncs;
@ProvidesInterface(action = GlobalActions.ACTION, version = GlobalActions.VERSION)
@DependsOn(target = GlobalActionsManager.class)
public interface GlobalActions extends Plugin {
    String ACTION = "com.android.systemui.action.PLUGIN_GLOBAL_ACTIONS";
    int VERSION = 1;

    void showGlobalActions(GlobalActionsManager manager);
    default void showShutdownUi(boolean isReboot, String reason) {
    }
    @ProvidesInterface(version = GlobalActionsManager.VERSION)
    public interface GlobalActionsManager {
        int VERSION = 1;

        void onGlobalActionsShown();
        void onGlobalActionsHidden();

        void shutdown();
        void reboot(boolean safeMode);
    }
}

该接口在

frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
public class GlobalActionsComponent extends SystemUI implements Callbacks, GlobalActionsManager {
...
...
    private IStatusBarService mBarService;
    @Override
    public void start() {
        mBarService = IStatusBarService.Stub.asInterface(
                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
...
...
    }
...
...
    @Override
    public void shutdown() {
        try {
            mBarService.shutdown();
        } catch (RemoteException e) {
        }
    }
    @Override
    public void reboot(boolean safeMode) {
        try {
            mBarService.reboot(safeMode);
        } catch (RemoteException e) {
        }
    }
}

而IStatusBarService通过binder的远程实现就是StatusBarManagerService ,而StatusBarManagerService 是在SystemServer中创建的

/**
 * A note on locking:  We rely on the fact that calls onto mBar are oneway or
 * if they are local, that they just enqueue messages to not deadlock.
 */
public class StatusBarManagerService extends IStatusBarService.Stub {
...
...
...
    /**
     * Allows the status bar to shutdown the device.
     */
    @Override
    public void shutdown() {
        enforceStatusBarService();
        long identity = Binder.clearCallingIdentity();
        try {
            // ShutdownThread displays UI, so give it a UI context.
            mHandler.post(() ->
                    ShutdownThread.shutdown(getUiContext(),
                        PowerManager.SHUTDOWN_USER_REQUESTED, false));
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }
...
    /**
     * Allows the status bar to reboot the device.
     */
    @Override
    public void reboot(boolean safeMode) {
        enforceStatusBarService();
        long identity = Binder.clearCallingIdentity();
        try {
            mHandler.post(() -> {
                // ShutdownThread displays UI, so give it a UI context.
                if (safeMode) {
                    ShutdownThread.rebootSafeMode(getUiContext(), true);
                } else {
                    ShutdownThread.reboot(getUiContext(),
                            PowerManager.SHUTDOWN_USER_REQUESTED, false);
                }
            });
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

reboot和shutdown的具体操作是在ShutdownThread 中完成,看一下ShutdownThread的具体实现

frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java
    private static AlertDialog sConfirmDialog;

    public static void shutdown(final Context context, String reason, boolean confirm) {
        mReboot = false;
        mRebootSafeMode = false;//不是重启
        mReason = reason;
        shutdownInner(context, confirm);
    }
// 具体执行shutdownInner 
private static void shutdownInner(final Context context, boolean confirm) {
....
   beginShutdownSequence(context);
....
}
///
    public static void rebootSafeMode(final Context context, boolean confirm) {
        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
        if (um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
            return;
        }

        mReboot = true;
        mRebootSafeMode = true;
        mRebootHasProgressBar = false;
        mReason = null;
        shutdownInner(context, confirm);
    }
....
....
    public static void reboot(final Context context, String reason, boolean confirm) {
        mReboot = true;
        mRebootSafeMode = false;
        mRebootHasProgressBar = false;
        mReason = reason;
        shutdownInner(context, confirm);
    }
...
这两个后面调用也都是shutdownInner,confirm来确认是否需要再创建关机dialog

在beginShutdownSequence中通过添加PARTIAL_WAKE_LOCK锁防止手机进入休眠状态

private static void beginShutdownSequence(Context context) {
...
...
        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);
        } catch (SecurityException e) {
            Log.w(TAG, "No permission to acquire wake lock", e);
            sInstance.mCpuWakeLock = null;
        }
...
...
            // start the thread that initiates shutdown
            sInstance.mHandler = new Handler() {
            };
            sInstance.start();
...
...
}

线程运行,在里面发送关机广播,关闭ActivityManagerService,PackageManagerService,MountService等服务最后执行

01-01 01:33:24.844759   587  3946 I ShutdownThread: Shutting down activity manager...
01-01 01:33:25.318104   587  3946 I ShutdownThread: Shutting down package manager...
01-01 01:33:25.368304   587  4099 W ShutdownThread: Turning off cellular radios...
01-01 01:33:25.490202   587  4099 I ShutdownThread: Waiting for NFC, Bluetooth and Radio...
01-01 01:33:25.994807   949  1154 V PhoneInterfaceManager: [PhoneIntfMgr] 2 Phones are shutdown.
01-01 01:33:25.995463   587  4099 I ShutdownThread: Radio turned off.
01-01 01:33:25.995914   587  4099 I ShutdownThread: NFC, Radio and Bluetooth shutdown complete.
01-01 01:33:25.995914   587  4099 I ShutdownThread: NFC, Radio and Bluetooth shutdown complete.
01-01 01:33:25.999106   587  3946 I ShutdownThread: Shutting down StorageManagerService

rebootOrShutdown(mContext, mReboot, mReason);

mShutdownSeqFinish为MTK客制化的MTKShutdownThread中执行客制化动画的包括

关机动画线程延时
shutdownAnimationService
//Turn backlight off
关闭背光灯
setBacklightOff();执行PowerMangerService中的goToSleep
    /**
     * 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") + (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");
        }
        Log.i(TAG, "Sending shutdown broadcast...");
        //发送关机广播
        Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND
                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        mContext.sendOrderedBroadcastAsUser(intent,
                UserHandle.ALL, null, br, mHandler, 0, null, null);
...
...
        final IActivityManager am =
                IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
        if (am != null) {
            try {
                am.shutdown(MAX_BROADCAST_TIME);
            } catch (RemoteException e) {
            }
        }
....
        ///M: added for Shutdown Enhancement@{
        mShutdownSeqFinish(mContext);
        /// @}
....
        rebootOrShutdown(mContext, mReboot, mReason);
}

看一下ActivityManagerService中shutdown所执行的操作

    @Override
    public boolean shutdown(int timeout) {
...
        boolean timedout = false;

        synchronized(this) {
            mShuttingDown = true;
            mStackSupervisor.prepareForShutdownLocked();
//
            updateEventDispatchingLocked();
            timedout = mStackSupervisor.shutdownLocked(timeout);
        }
        mAppOpsService.shutdown();
        if (mUsageStatsService != null) {
            mUsageStatsService.prepareShutdown();
        }
        mBatteryStatsService.shutdown();
        synchronized (this) {
            mProcessStats.shutdownLocked();
            notifyTaskPersisterLocked(null, true);
        }

        return timedout;
    }

 

在rebootOrShutdown会执行PowerManagerService中的lowLevelReboot和lowLevelShutdown方法

frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java  
  
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
        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 {
            //SHUTDOWN_VIBRATE_MS大概200毫秒
                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);
            }
...
        }
        // Shutdown power
        Log.i(TAG, "Performing low-level shutdown...");
        PowerManagerService.lowLevelShutdown(reason);//关闭电源
}
    public static void lowLevelReboot(String reason) {
        if (reason == null) {
            reason = "";
        }
        // If the reason is "quiescent", it means that the boot process should proceed
        // without turning on the screen/lights.
        // The "quiescent" property is sticky, meaning that any number
        // of subsequent reboots should honor the property until it is reset.
        if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
            sQuiescent = true;
            reason = "";
        } else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {
            sQuiescent = true;
            reason = reason.substring(0,
                    reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);
        }
        if (reason.equals(PowerManager.REBOOT_RECOVERY)
                || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
            reason = "recovery";
        }
        if (sQuiescent) {
            // Pass the optional "quiescent" argument to the bootloader to let it know
            // that it should not turn the screen/lights on.
            reason = reason + ",quiescent";
        }
        SystemProperties.set("sys.powerctl", "reboot," + reason);
        try {
            Thread.sleep(20 * 1000L);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
    }

而在PowerManagerService的

lowLevelReboot的 SystemProperties.set("sys.powerctl", "reboot," + reason);

类型如何:

sys.powerctl = reboot,

sys.powerctl = reboot,recovery

而lowLevelShutdown只是往SystemProperties.set("sys.powerctl", "shutdown," + reason);

类型例如:
sys.powerctl = shutdown, userrequested
sys.powerctl = shutdown, 
    /**
     * Low-level function turn the device off immediately, without trying
     * to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown.
     *
     * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.
     */    
public static void lowLevelShutdown(String reason) {
        if (reason == null) {
            reason = "";
        }
        SystemProperties.set("sys.powerctl", "shutdown," + reason);
    }

通过SystemProperties把设置sys.powerctl这个字段的值往下传递,在init.cpp中

shutdown_command保存value (手动关机为:shutdown, userrequested)

 

do_shutdown则置为true
system/core/init/init.cpp
void property_changed(const std::string& name, const std::string& value) {
    // If the property is sys.powerctl, we bypass the event queue and immediately handle it.
    // This is to ensure that init will always and immediately shutdown/reboot, regardless of
    // if there are other pending events to process or if init is waiting on an exec service or
    // waiting on a property.
    // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
    // commands to be executed.
    if (name == "sys.powerctl") {
        // Despite the above comment, we can't call HandlePowerctlMessage() in this function,
        // because it modifies the contents of the action queue, which can cause the action queue
        // to get into a bad state if this function is called from a command being executed by the
        // action queue.  Instead we set this flag and ensure that shutdown happens before the next
        // command is run in the main init loop.
        // TODO: once property service is removed from init, this will never happen from a builtin,
        // but rather from a callback from the property service socket, in which case this hack can
        // go away.
        shutdown_command = value;
        do_shutdown = true;
    }
    if (property_triggers_enabled) 
    ActionManager::GetInstance().QueuePropertyChange(name, value);
    if (waiting_for_prop) {
        if (wait_prop_name == name && wait_prop_value == value) {
            LOG(INFO) << "Wait for property took " << *waiting_for_prop;
            ResetWaitForProp();
        }
    }
}

在init.cpp的main函数while(true)的HandlePowerctlMessage接收value值做具体的关机操作

int main(int argc, char** argv) {
....
    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);

    if (is_first_stage) {
...
     while (true) {
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1;
...
...
        if (do_shutdown && !shutting_down) {
            do_shutdown = false;
            if (HandlePowerctlMessage(shutdown_command)) {
                shutting_down = true;
            }
        }
...
...

}

而HandlePowerctlMessage是在system/core/init/reboot.cpp

command匹配shutdown,reboot等之后,将cmd设值成对应的值传入

DoReboot(cmd, command, reboot_target, run_fsck);
bool HandlePowerctlMessage(const std::string& command) {
    unsigned int cmd = 0;
    std::vector<std::string> cmd_params = android::base::Split(command, ",");
    std::string reboot_target = "";
    bool run_fsck = false;
    bool command_invalid = false;
    if (cmd_params.size() > 3) {
        command_invalid = true;
    } else if (cmd_params[0] == "shutdown") {
        cmd = ANDROID_RB_POWEROFF;
        if (cmd_params.size() == 2 && cmd_params[1] == "userrequested") {
            // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
            // Run fsck once the file system is remounted in read-only mode.
            run_fsck = true;
        }
    } else if (cmd_params[0] == "reboot") {
        cmd = ANDROID_RB_RESTART2;
        if (cmd_params.size() >= 2) {
            reboot_target = cmd_params[1];
            // When rebooting to the bootloader notify the bootloader writing
            // also the BCB.
            if (reboot_target == "bootloader") {
                std::string err;
                if (!write_reboot_bootloader(&err)) {
                    LOG(ERROR) << "reboot-bootloader: Error writing "
                                  "bootloader_message: "
                               << err;
                }
            }
            // If there is an additional bootloader parameter, pass it along
            if (cmd_params.size() == 3) {
                reboot_target += "," + cmd_params[2];
            }
        }
    } else if (command == "thermal-shutdown") {  // no additional parameter allowed
        // run_fsck is false to avoid delay
        cmd = ANDROID_RB_THERMOFF;
    } else {
        command_invalid = true;
    }
...
...
    LOG(INFO) << "Clear action queue and start shutdown trigger";
    ActionManager::GetInstance().ClearQueue();
    // Queue shutdown trigger first
    ActionManager::GetInstance().QueueEventTrigger("shutdown");
    // Queue built-in shutdown_done
    auto shutdown_handler = [cmd, command, reboot_target,
                             run_fsck](const std::vector<std::string>&) {
        DoReboot(cmd, command, reboot_target, run_fsck);
        return 0;
    };
    ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");

    // Skip wait for prop if it is in progress
    ResetWaitForProp();

    // Skip wait for exec if it is in progress
    if (ServiceManager::GetInstance().IsWaitingForExec()) {
        ServiceManager::GetInstance().ClearExecWait();
    }

    return true;
}
void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
              bool runFsck) {
...
...
    ServiceManager::GetInstance().ForEachService([&kill_after_apps, &to_starts](Service* s) {
        if (kill_after_apps.count(s->name())) {
            s->SetShutdownCritical();
        } else if (to_starts.count(s->name())) {
            s->Start();
            s->SetShutdownCritical();
        } else if (s->IsShutdownCritical()) {
            s->Start();  // start shutdown critical service if not started
        }
    });
....
    Service* bootAnim = ServiceManager::GetInstance().FindServiceByName("bootanim");
    Service* surfaceFlinger = ServiceManager::GetInstance().FindServiceByName("surfaceflinger");
    if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
        ServiceManager::GetInstance().ForEachServiceInClass("animation", [](Service* s) {
            s->SetShutdownCritical();  // will not check animation class separately
        });
    }
...
    // optional shutdown step
    // 1. terminate all services except shutdown critical ones. wait for delay to finish
    if (shutdown_timeout > 0ms) {
...
        // Ask all services to terminate except shutdown critical ones.
        ServiceManager::GetInstance().ForEachService([](Service* s) {
            if (!s->IsShutdownCritical()) s->Terminate();
        });
...
     }
...
    // minimum safety steps before restarting
    // 2. kill all services except ones that are necessary for the shutdown sequence.
    ServiceManager::GetInstance().ForEachService([](Service* s) {
        if (!s->IsShutdownCritical()) s->Stop();
    });
    ServiceManager::GetInstance().ReapAnyOutstandingChildren();

    // 3. send volume shutdown to vold
    Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
    if (voldService != nullptr && voldService->IsRunning()) {
        ShutdownVold();
        voldService->Stop();
    } else {
        LOG(INFO) << "vold not running, skipping vold shutdown";
    }
    // logcat stopped here
    ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
        if (kill_after_apps.count(s->name())) s->Stop();
    });
    // 4. sync, try umount, and optionally run fsck for user shutdown
    sync();
    UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
    // Follow what linux shutdown is doing: one more sync with little bit delay
    sync();
    if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
    LogShutdownTime(stat, &t);
    // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
    RebootSystem(cmd, rebootTarget);
    abort();
}
static void __attribute__((noreturn))
RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
    LOG(INFO) << "Reboot ending, jumping to kernel";
....
    switch (cmd) {
        case ANDROID_RB_POWEROFF:
            reboot(RB_POWER_OFF);
            break;

        case ANDROID_RB_RESTART2:
            syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                    LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
            break;

        case ANDROID_RB_THERMOFF:
            reboot(RB_POWER_OFF);
            break;
    }
    // In normal case, reboot should not return.
    PLOG(FATAL) << "reboot call returned";
    abort();
}

进入kernel,kernel-4.4/kernel/reboot.c

/*
 * Reboot system call: for obvious reasons only root may call it,
 * and even root needs to set up some magic numbers in the registers
 * so that some mistake won't make this reboot the whole machine.
 * You can also set the meaning of the ctrl-alt-del-key here.
 *
 * reboot doesn't sync: do that yourself before calling this.
 */
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
                void __user *, arg)
{
...
...
        switch (cmd) {
        case LINUX_REBOOT_CMD_RESTART:
                kernel_restart(NULL);
                break;

        case LINUX_REBOOT_CMD_CAD_ON:
                C_A_D = 1;
                break;
        case LINUX_REBOOT_CMD_CAD_OFF:
                C_A_D = 0;
                break;

        case LINUX_REBOOT_CMD_HALT:
                kernel_halt();
                do_exit(0);
                panic("cannot halt");

        case LINUX_REBOOT_CMD_POWER_OFF:
                kernel_power_off();
                do_exit(0);
                break;

        case LINUX_REBOOT_CMD_RESTART2:
                ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
                if (ret < 0) {
                        ret = -EFAULT;
                        break;
                }
                buffer[sizeof(buffer) - 1] = '\0';

                kernel_restart(buffer);
                break;
....
}

从串口log上看[sys.powerctl]=[shutdown,userrequested]设置完成

[  326.688377] <3>.(2)[1:init]init: PropSet [sys.powerctl]=[shutdown,userrequested] Done
[  326.688451] <3>.(2)[1:init][name:socket&][mtk_net][socekt]socket_close[64932] refcnt: 3
[  326.688585] <3>.(2)[1:init]init: Clear action queue and start shutdown trigger
[  326.688794] <3>.(2)[1:init]init: processing action (shutdown_done) from (<Builtin Action>:0)
[  326.688857] <3>.(2)[1:init]init: Reboot start, reason: shutdown,userrequested, rebootTarget: 
[  326.689690] <3>.(2)[1:init]init: Shutdown timeout: 0 ms
[  326.689918] <3>.(2)[1:init]init: Sending signal 9 to service 'healthd' (pid 278) process group...
.......
 [  329.700482] <0>.(0)[1:init]init: Sending signal 9 to service 'lmkd' (pid 280) process group...
[  330.136580] <2>.(2)[1:init]init: Sending signal 9 to service 'vold' (pid 241) process group...
[  330.218627] <1>.(1)[1:init]init: Sending signal 9 to service 'adbd' (pid 316) process group...
 [  330.234608] <1>.(1)[1:init]init: Sending signal 9 to service 'logd' (pid 229) process group...

 

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值