android关机流程

android关机流程

PhoneWindowManager.java接收到长按power按键

PhoneWindowManager.java

   public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
   。。。
           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);
                }
                break;
            }
           }
   }

在这里interceptPowerKeyDown延时发送关机的message,interceptPowerKeyUp是取消延时的message。如果取消到达时间内没有发送出去就被取消了。

    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
        。。。
                        if (hasLongPressOnPowerBehavior()) {
                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageDelayed(msg,
                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                }
    }

    private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
    final boolean handled = canceled || mPowerKeyHandled;
    mScreenshotChordPowerKeyTriggered = false;
    cancelPendingScreenshotChordAction();
    cancelPendingPowerKeyAction();
    。。
    }

    private void cancelPendingPowerKeyAction() {
    if (!mPowerKeyHandled) {
        mPowerKeyHandled = true;
        mHandler.removeMessages(MSG_POWER_LONG_PRESS);
        }
    }    



处理延时发送的Message,调用showGlobalActionsInternal,如果时间不够,达不到长按就remove掉message。

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

    private void powerLongPress() {
            showGlobalActionsInternal();
    }


    void showGlobalActionsInternal() {
        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
        if (mGlobalActions == null) {
            mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
        }
        final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
        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);
        }
    }
GlobalActions,弹出dialog,又systemui或者系统弹出

如果5秒内systemui弹出失败,关机对话框将由系统弹出。

GlobalActions.java

GlobalActionsclass 
implements GlobalActionsListener {

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

    @Override
    public void onGlobalActionsShown() {
        if (DEBUG) Slog.d(TAG, "onGlobalActionsShown");
        // SysUI is showing, remove timeout callbacks.
        mHandler.removeCallbacks(mShowTimeout);
    }    

}

上面mStatusBarInternal.showGlobalActions();调用的SystemUI的对话框,操作在SystemuI内完成。他由LocalServices获取。

    public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
        mContext = context;
        mHandler = new Handler();
        mWindowManagerFuncs = windowManagerFuncs;
        mStatusBarInternal = LocalServices.getService(StatusBarManagerInternal.class);

        // Some form factors do not have a status bar.
        if (mStatusBarInternal != null) {
            mStatusBarInternal.setGlobalActionsListener(this);
        }
    }

StatusBarManagerInternal是一个接口,那么获取的上面mStatusBarInternal对象应该是实现了StatusBarManagerInternal接口。

//添加service,与getService对应
    public StatusBarManagerService(Context context, WindowManagerService windowManager) {
        mContext = context;
        mWindowManager = windowManager;

        LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
    }
    /**
     * Private API used by NotificationManagerService.
     */
    private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {
        private boolean mNotificationLightOn;
        。。。
                @Override
        public void showGlobalActions() {
            if (mBar != null) {
                try {
                    mBar.showGlobalActionsMenu();
                } catch (RemoteException ex) {}
            }
        }
        。。。
    }

这个mBar定义IStatusBar mBar,是一个跨进程的操作,从注解我们可以看出IStatusBar,来源status bar service.

SystemUI实现

CommandQueue.java


    @Override
    public void showGlobalActionsMenu() {
        synchronized (mLock) {
            mHandler.removeMessages(MSG_SHOW_GLOBAL_ACTIONS);
            mHandler.obtainMessage(MSG_SHOW_GLOBAL_ACTIONS).sendToTarget();
        }
    }

GlobalActionsComponent.java

public class GlobalActionsComponent extends SystemUI implements Callbacks, GlobalActionsManager {

    private Extension<GlobalActions> mExtension;
    private IStatusBarService mBarService;

    @Override
    public void start() {
        mBarService = IStatusBarService.Stub.asInterface(
                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
        mExtension = Dependency.get(ExtensionController.class).newExtension(GlobalActions.class)
                .withPlugin(GlobalActions.class)
                .withDefault(() -> new GlobalActionsImpl(mContext))
                .build();
        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this);
    }

    @Override
    public void handleShowGlobalActionsMenu() {
        mExtension.get().showGlobalActions(this);
    }
}

最终:

public class GlobalActionsImpl implements GlobalActions {

    private final Context mContext;
    private final KeyguardMonitor mKeyguardMonitor;
    private final DeviceProvisionedController mDeviceProvisionedController;
    private GlobalActionsDialog mGlobalActions;

    public GlobalActionsImpl(Context context) {
        mContext = context;
        mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
        mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
    }

    @Override
    public void showGlobalActions(GlobalActionsManager manager) {
        if (mGlobalActions == null) {
            final ContextThemeWrapper context = new ContextThemeWrapper(mContext,
                    android.R.style.Theme_Material_Light);
            mGlobalActions = new GlobalActionsDialog(context, manager);
        }
        mGlobalActions.showDialog(mKeyguardMonitor.isShowing(),
                mDeviceProvisionedController.isDeviceProvisioned());
    }
}

GlobalActionsDialog负责显示关机,重启的对话框,在这里我们可以自定义关机对话框。
这里面对于关机,重启,安全模式是调用系统api完成的

//关机
mWindowManagerFuncs.shutdown();
//以安全模式重启
mWindowManagerFuncs.reboot(true);
//重启
mWindowManagerFuncs.reboot(false);

具体重启是如何操作,再看mWindowManagerFuncs对象的实现类GlobalActionsComponent。

GlobalActionsComponent.java

    @Override
    public void reboot(boolean safeMode) {
        try {
            mBarService.reboot(safeMode);
        } catch (RemoteException e) {
        }
    }

mBarService的实现类
StatusBarManagerService.java

     */
    @Override
    public void reboot(boolean safeMode) {
        enforceStatusBarService();
        long identity = Binder.clearCallingIdentity();
        try {
            mHandler.post(() -> {
                // ShutdownThread displays UI, so give it a UI context.
                // TINNO START
                // Modified by Jameson.xu on 20171114 for VBNLITEIA-1113,device reset exception
                if (safeMode) {
                    //ShutdownThread.rebootSafeMode(getUiContext(), false);
                    //safe reboot,should show dialog for user(CTS 3PL(windware) need);for safemode function,CDAAOB-224,DATE20180825
                    ShutdownThread.rebootSafeMode(getUiContext(), true);
                } else {
                    ShutdownThread.reboot(getUiContext(),
                            PowerManager.SHUTDOWN_USER_REQUESTED, true);
                }
                // TINNO END
            });
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }


    /**
     * 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.
            // TINNO START
            // Modified by Jameson.xu on 20171114 for VBNLITEIA-1113,device reset exception
            mHandler.post(() ->
                    ShutdownThread.shutdown(getUiContext(),
                        PowerManager.SHUTDOWN_USER_REQUESTED, true));
            // TINNO END
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

最终在ShutdownThread处理
修改安全模式,关机。重启的提示就是在这里面了

ShutdownThread.java

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

    /**
     * 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 the kernel (e.g. "recovery"), or null.
     * @param confirm true if user confirmation is needed before shutting down.
     */
    public static void reboot(final Context context, String reason, boolean confirm) {
        mReboot = true;
        mRebootSafeMode = false;
        mRebootHasProgressBar = false;
        mReason = reason;
        shutdownInner(context, confirm);
    }

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

        final int longPressBehavior = context.getResources().getInteger(
                        com.android.internal.R.integer.config_longPressOnPowerBehavior);

        // TINNO BEGIN
        // Modified by marco.ma, for global reboot function, VBNLITEIA-491, DATE20171103
        int resourceId = 0;

        if (!TinnoFeature.FEATURE_REBOOT_DIALOG) {
            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);
        }
        // TINNO END

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

        // TINNO BEGIN
        // Added by marco.ma, for global reboot function, VBNLITEIA-491, DATE20171103
        int resourceIdTitle = 0;
        int resourceIdMsg = 0;

        if (TinnoFeature.FEATURE_REBOOT_DIALOG) {
            if (mReboot && !mRebootSafeMode) {
                resourceIdTitle = com.android.internal.R.string.reboot;
                resourceIdMsg = longPressBehavior == 2
                            ? com.android.internal.R.string.reboot_confirm_question
                            : com.android.internal.R.string.reboot_confirm;
            } else if (mRebootSafeMode) {
                resourceIdTitle = com.android.internal.R.string.reboot_safemode_title;
                resourceIdMsg = com.android.internal.R.string.reboot_safemode_confirm;
            } else {
                resourceIdTitle = com.android.internal.R.string.power_off;
                resourceIdMsg = longPressBehavior == 2
                            ? com.android.internal.R.string.shutdown_confirm_question
                            : com.android.internal.R.string.shutdown_confirm;
            }
        }
        // TINNO END

        if (confirm) {
            final CloseDialogReceiver closer = new CloseDialogReceiver(context);
            if (sConfirmDialog != null) {
                sConfirmDialog.dismiss();
            }
            // TINNO BEGIN
            // Modified by marco.ma, for global reboot function, VBNLITEIA-491, DATE20171103
            sConfirmDialog = new AlertDialog.Builder(context)
                    .setTitle(TinnoFeature.FEATURE_REBOOT_DIALOG 
                            ? resourceIdTitle 
                            : (mRebootSafeMode
                                    ? com.android.internal.R.string.reboot_safemode_title
                                    : com.android.internal.R.string.power_off))
                    .setMessage(TinnoFeature.FEATURE_REBOOT_DIALOG ? resourceIdMsg : resourceId)
                    .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            beginShutdownSequence(context);
                        }
                    })
                    .setNegativeButton(com.android.internal.R.string.no, null)
                    .create();
            // TINNO END
            closer.dialog = sConfirmDialog;
            sConfirmDialog.setOnDismissListener(closer);
            sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
            sConfirmDialog.show();
            } else {
                beginShutdownSequence(context);
            }
        }

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

上面那个类,包含关机动画,等许多操作,最后都会调用

PowerManagerService.lowLevelReboot(reason);
PowerManagerService.lowLevelShutdown(reason);


   /**
     * 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.set(“sys.powerctl”, “reboot,” + reason);或
SystemProperties.set(“sys.powerctl”, “shutdown,” + reason);通知 通知init 执行。

然后到源码System目录init.cpp ,reboot.cpp处理这些关机操作。

猜你喜欢

转载自blog.csdn.net/w1764662543/article/details/82190412