【2017年学习输出内容记录】Andriod系统关机流程-从按下关机键到完成关机任务

Andriod系统关机流程-从按下关机键到完成关机任务


一、

正常关机一般就是长按电源键,然后系统弹出个对话框,选择Power off则开始关机。电源键是系统级别的按键,所以对按键事件的响应不在某一个app中,而是在PhoneWindowManager的dispatchUnhandledKey方法中。

frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java:

/** {@inheritDoc} */
    @Override
    public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
        // Note: This method is only called if the initial down was unhandled.
...
                if (!interceptFallback(win, fallbackEvent, policyFlags)) {
                    fallbackEvent.recycle();
                    fallbackEvent = null;
                }
...
    }
系统按键的处理逻辑被下放到了interceptFallback方法中。

private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
        int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
        if ((actions & ACTION_PASS_TO_USER) != 0) {
            long delayMillis = interceptKeyBeforeDispatching(
                    win, fallbackEvent, policyFlags);
            if (delayMillis == 0) {
                return true;
            }
        }
        return false;
    }
通过分析interceptFallback方法的源码,发现电源按键的处理逻辑在interceptKeyBeforeQueueing方法中,所以继续看一下interceptKeyBeforeQueueing方法。

/** {@inheritDoc} */
    @Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        if (!mSystemBooted) { //如果没有boot,则不做处理
            // If we have not yet booted, don't let key events do anything.
            return 0;
        }


        /// M: If USP service freeze display, disable power key
        if (interceptKeyBeforeHandling(event)) { //如果USP服务冻结显示,禁用电源键
            return 0;
        }


        /// M: power-off alarm, disable power_key @{
        if (KeyEvent.KEYCODE_POWER == event.getKeyCode() && mIsAlarmBoot) { //断电警告,禁用电源键
            return 0;
        }
        /// @}
...
        //add by liuhao for home key to wakeup
        if ( keyCode == KeyEvent.KEYCODE_HOME && !isScreenOn()) { //添加用home键唤醒手机的功能
            policyFlags |= WindowManagerPolicy.FLAG_WAKE;
        }
...
        // Handle special keys.
        switch (keyCode) {
...
            case KeyEvent.KEYCODE_POWER: { //关于电源按键的处理逻辑
                result &= ~ACTION_PASS_TO_USER;
                isWakeKey = false; // wake-up will be handled separately
                if (down) {
                    /* 360OS begin */
                    /* add for FEATURE_SYS_SCREENRECORD FEATURE_SYSTEMUI_MISTOUCH_PREVENTION */
                    if (interactive && mQikuPhoneWindowManager != null && !mQikuPhoneWindowManager.ismPowerKeyTriggered()
                            && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {


                      long keyPowerForMistouchAndScreenRecord =
                        mQikuPhoneWindowManager.qiku_keyPowerForMistouchAndScreenRecord(SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS,event.getDownTime());
                        if(keyPowerForMistouchAndScreenRecord == -1){
                            break;
                        }
                        mQikuPhoneWindowManager.qiku_interceptScreenshotLog(mScreenshotChordEnabled,SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS);
                    }
                    /* 360OS end */
                    interceptPowerKeyDown(event, interactive); //当电源按下时调用了interceptPowerKeyDown,在这之前360OS做了自定义
                } else {
                    //360OS begin
                    if (SystemProperties.getBoolean("gesture.enable_sos_launch", false) ) {
                            touchToSos();
                        }
                    //360OS end 


                    /* 360OS begin */
                    /* add for FEATURE_SYS_SCREENRECORD */
                    if (null != mQikuPhoneWindowManager) {
                        mQikuPhoneWindowManager.qiku_cancelPendingStartAndsetmPowerKeyTriggered();
                    }
                    /* 360OS end */


                    interceptPowerKeyUp(event, interactive, canceled); //当电源键抬起时调用了interceptPowerKeyUp,在这之前360OS也做了自定义
                }
                break;
            }
...
        }
    }

private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
        //add by topwise liudongming begin
        String bootReason = SystemProperties.get("sys.boot.reason.ext");
        boolean ret = (bootReason != null && bootReason.equals("1")) ? true : false;
        if (!ret) {
            //add by topwise liudongming end
            // Hold a wake lock until the power key is released.
            if (!mPowerKeyWakeLock.isHeld()) { // mPowerKeyWakeLock为PARTIAL_WAKE_LOCK级别的锁
                mPowerKeyWakeLock.acquire(); //将调用到PowerManagerService的acquire WakeLock流程
            }


            // Cancel multi-press detection timeout.
//处理多次按power键的场景
//每次power up时,发送MSG_POWER_DELAYED_PRESS的延迟消息
//如果延迟消息被处理,说明一次完整的Power键处理结束(按下去,弹起来)
//在延迟消息被处理前,再次按power键,就检测到多次点击了
            if (mPowerKeyPressCounter != 0) {
                mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
            }


            // Detect user pressing the power button in panic when an application has
            // taken over the whole screen. 当应用程序接管整个屏幕时,检测用户在紧急情况下按下电源按钮。误触?
            boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
                    SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags));
            if (panic) {
                mHandler.post(mHiddenNavPanic);
            }


            // Latch power key state to detect screenshot chord.
//如果当前是亮屏状态,且满足触发截屏的条件,触发截屏功能
            if (interactive && !mScreenshotChordPowerKeyTriggered
                    && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                mScreenshotChordPowerKeyTriggered = true;
                mScreenshotChordPowerKeyTime = event.getDownTime();
                interceptScreenshotChord();
            }


            // Stop ringing or end call if configured to do so when power is pressed.
            TelecomManager telecomManager = getTelecommService();
            boolean hungUp = false;
            if (telecomManager != null) {
                if (telecomManager.isRinging()) { //如果有电话呼入
                    // Pressing Power while there's a ringing incoming
                    // call should silence the ringer.
                    telecomManager.silenceRinger(); //设置电话响铃静音
                } else if ((mIncallPowerBehavior
                        & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
                        && telecomManager.isInCall() && interactive) { //如果正在接听电话,配置了Power键挂断电话,当前是亮屏状态
                    // Otherwise, if "Power button ends call" is enabled,
                    // the Power button will hang up any current active call.
                    hungUp = telecomManager.endCall(); //按Power按键挂断正在接听的电话
                }
            }


            GestureLauncherService gestureService = LocalServices.getService(GestureLauncherService.class);
            boolean gesturedServiceIntercepted = false;
            if (gestureService != null) { //手势对应的服务,尝试拦截处理Power键动作事件
                //360OS begin
                if (!SystemProperties.getBoolean("gesture.enable_sos_launch", false)) {
                    gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive, mTmpBoolean);
                }
                //360OS end
                if (mTmpBoolean.value && mGoingToSleep) {
                    mCameraGestureTriggeredDuringGoingToSleep = true;
                }
            }


            // 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
                    || mScreenshotChordVolumeUpKeyTriggered || 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()) { //1、判断是否支持长按行为
                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); //2、发送MSG_POWER_LONG_PRESS消息
                        msg.setAsynchronous(true);
                        mHandler.sendMessageDelayed(msg,
                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); //3、发送delay消息,给用户一些时间长按power键显示关机dialog, 同时delay时间也可以通过config.xml中配置  
                    }
                } else { //当前不是亮屏状态
                    wakeUpFromPowerKey(event.getDownTime()); //唤醒系统


                    if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) { //1、判断支持长按行为,并且支持息屏长按
                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); //2、发送MSG_POWER_LONG_PRESS消息
                        msg.setAsynchronous(true);
                        mHandler.sendMessageDelayed(msg,
                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                        mBeganFromNonInteractive = true; //3、设置从息屏状态开始的标识为true
                    } else {
                        final int maxCount = getMaxMultiPressPowerCount(); //多次按下计数,默认返回1


                        if (maxCount <= 1) { //息屏时,按下power键(不弹起),仅消耗掉该事件
                            mPowerKeyHandled = true;
                        } else {
                            mBeganFromNonInteractive = true; //设置从息屏状态开始的标识为true
                        }
                    }
                }
            }
        }
    }
在if(interactive)分支,我们发送一个一个异步消息,并且msg的what为MSG_POWER_LONG_PRESS,即长按电源事件的异步消息。看一下mHandler的handleMessage方法对该what消息的处理逻辑。

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

当msg的what为MSG_POWER_LONG_PRESS时我们调用了powerLongPress方法,这个方法应该就是处理电源按键长按的逻辑。

private void powerLongPress() {
        final int behavior = getResolvedLongPressOnPowerBehavior(); //根据长按行为behavior来分情况处理
        switch (behavior) {
        case LONG_PRESS_POWER_NOTHING: //长按Power键不作处理
            break;
        case LONG_PRESS_POWER_GLOBAL_ACTIONS: //为全局动作,显示关机Dialog,正常流程
            mPowerKeyHandled = true; 标识按下电源键的事件已经进行处理
            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
                performAuditoryFeedbackForAccessibilityIfNeed();
            }
            showGlobalActionsInternal(); //显示全局的dialog 
            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;
        }
    }

正常关机流程调用showGlobalActionsInternal()方法,弹出选择要进行的操作界面。

void showGlobalActionsInternal() {
        qiku_showGlobalActionsInternal();
    }
    /* 360OS begin */
    void qiku_showGlobalActionsInternal(){
        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); //请求ActivityManagerNative关闭系统所有窗口
        final boolean keyguardShowing = isKeyguardShowingAndNotOccluded(); //keyguard是否在显示
        /* 360OS begin */
        mQikuPhoneWindowManager.qiku_showGlobalActionsInternal(mContext, mWindowManagerFuncs, keyguardShowing, isDeviceProvisioned()); //360OS定制的方法,目的也是显示关机对话框
        /* 360OS end */
        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); //通知power发生了一次用户时间, 让用户可以看到dialog
        }
    }
    /* 360OS end */

首先调用了sendCloseSystemWindows方法,该方法用于关机系统弹窗,比如输入法,壁纸等。关键函数在于360OS定制的一个函数,源生安卓在这里先创建并初始化GlobalActions,然后调用了GlobalActions的方法:

if (mGlobalActions == null) {
        //初始化GlobalActions
        mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
    }
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());

其作用是显示关机对话框,360OS源码没法查看,但是可以肯定的是360OS定制了自己的一些UI,显示关机对话框是其必然会有的过程,所以这里根据源生Android的代码继续进行分析。

frameworks\base\services\core\java\com\android\server\policy\GlobalActions.java:

/**
     * 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(); //如果不存在mDialog, 就调用handleShow处理
        }
    }
在showDialog方法中我们首先判断mDialog是否为空,若为空则发送msg的what为MESSAGE_SHOW的异步消息,否则调用handleShow方法。

private void handleShow() {
        awakenIfNecessary();
        mDialog = createDialog(); //创建mDialog对象  
        prepareDialog(); //准备dialog


        // If we only have 1 item and it's a simple press action, just do this action.
        if (mAdapter.getCount() == 1 // 对话框视图只有一个item,当手单按时回调onPress()函数
                && mAdapter.getItem(0) instanceof SinglePressAction
                && !(mAdapter.getItem(0) instanceof LongPressAction)) {
            ((SinglePressAction) mAdapter.getItem(0)).onPress(); //调用onPress函数
        } else { //否则显示关机对话框,设置对话框参数属性
            WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
            attrs.setTitle("GlobalActions");
            mDialog.getWindow().setAttributes(attrs);
            mDialog.show(); //显示dialog  
            mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
        }
    }

方法体中调用了createDialog方法,创建了GlobalActionsDialog类型的mDialog。

/**
     * Create the global actions dialog.
     * @return A new dialog.
     */
    private GlobalActionsDialog createDialog() {
        ...
        mAirplaneModeOn = new ToggleAction(
                R.drawable.ic_lock_airplane_mode,
                R.drawable.ic_lock_airplane_mode_off,
                R.string.global_actions_toggle_airplane_mode,
                R.string.global_actions_airplane_mode_on_status,
                R.string.global_actions_airplane_mode_off_status) {
...
        }; //飞行模式
        onAirplaneModeChanged(); //飞行模式改变


        mItems = new ArrayList();
        String[] defaultActions = mContext.getResources().getStringArray(
                com.android.internal.R.array.config_globalActionsList); //获取action list记录在defaultActions数组中,可能包含飞行模式、关机、静音、重启等


        ArraySet addedKeys = new ArraySet();
        for (int i = 0; i < defaultActions.length; i++) { //遍历defaultActions列表
            String actionKey = defaultActions[i];
            if (addedKeys.contains(actionKey)) { //如果action已经在addedKeys列表中就不再添加了
                // If we already have added this, don't add it again.
                continue;
            }
            if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) { //对action list中action进行匹配,如果能匹配上就创建对应对象放入mItems列表中。关机
                mItems.add(new PowerAction()); //*封装关机操作
            } else if ("reboot".equals(actionKey)){ //重启
                mItems.add(new RebootAction()); //*封装重启操作
            } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) { //飞行模式
                mItems.add(mAirplaneModeOn);
            } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) { //上报bug
                if (Settings.Global.getInt(mContext.getContentResolver(),
                        Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
                    mItems.add(new BugReportAction());
                }
            } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) { //静音模式
                if (mShowSilentToggle) {
                    mItems.add(mSilentModeAction);
                }
            } else if ( ... ) {
...
} else {
                Log.e(TAG, "Invalid global action key " + actionKey);
            }
            // Add here so we don't add more than one.
            addedKeys.add(actionKey); //最后将actionKey放入列表, 不重复处理
        }


        mAdapter = new MyAdapter(); //创建适配器


        AlertParams params = new AlertParams(mContext);
        params.mAdapter = mAdapter;
        params.mOnClickListener = this;
        params.mForceInverseBackground = true;


        GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params); //创建dialog
        dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. 触摸对话框外部,对话框消失


//给对话框列表注册监听事件
        dialog.getListView().setItemsCanFocus(true);
        dialog.getListView().setLongClickable(true);
        dialog.getListView().setOnItemLongClickListener(
                new AdapterView.OnItemLongClickListener() {
                    @Override
                    public boolean onItemLongClick(AdapterView parent, View view, int position,
                            long id) {
                        final Action action = mAdapter.getItem(position);
                        if (action instanceof LongPressAction) {
                            return ((LongPressAction) action).onLongPress();
                        }
                        return false;
                    }
        });
        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);


        dialog.setOnDismissListener(this);


        return dialog; //将新建的dialog返回
    }

首先获得操作列表,可能包含:飞行模式、关机、静音模式、重启等等;然后轮训操作列表,并添加相应的Action;最后将这个操作列表保存到Dialog的adapter中并返回该dialog;然后回到handleShow方法,在得到返回的dialog之后调用了dialog的show方法,这样就显示出了电源长按操作界面。其中PowerAction和RebootAction分别封装了关机和重启操作。

private final class PowerAction extends SinglePressAction implements LongPressAction {
...
        @Override
        public void onPress() {
            // shutdown by making sure radio and power are handled accordingly.
            mWindowManagerFuncs.shutdown(false /* confirm */);
        }
    }

在PowerAction类的成员函数onPress方法中调用了mWindowManagerFuncs.showdown方法执行关机操作。这里的mWindowManagerFuncs成员变量是在GlobalActions的构造方法中赋值的。

/**
     * @param context everything needs a context :(
     */
    public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
        ...
        mWindowManagerFuncs = windowManagerFuncs;
...
    }

源生安卓代码在创建并初始化GlobalActions的时候直接传递了PhoneWindowManager的成员变量mWindowManagerFuncs。
if (mGlobalActions == null) {
        //初始化GlobalActions
        mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
    }

而mWindowManagerFuncs变量是在PhoneWindowManager的init方法中被初始化。

/** {@inheritDoc} */
    @Override
    public void init(Context context, IWindowManager windowManager,
            WindowManagerFuncs windowManagerFuncs) {
...
        mWindowManagerFuncs = windowManagerFuncs;
...
}

再次查找到PhoneWindowManager的init方法是在WindowManagerService中被调用。

frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java:

...
final WindowManagerPolicy mPolicy = new PhoneWindowManager(); //mPolicy是PhoneWindowManager的一个实例
...
private void initPolicy() {
        UiThread.getHandler().runWithScissors(new Runnable() {
            @Override
            public void run() {
                WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
                /// M: ANR mechanism for Message History/Queue for system server @{
                if ("eng".equals(Build.TYPE)) {
                    Looper.myLooper().setMessageLogging(
                            ANRAppManager.getDefault(
                                    new ANRAppFrameworks())
                                    .newMessageLogger(false, Thread.currentThread().getName()));
                }
                /// M: ANR mechanism for Message History/Queue for system server @}
                mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this); //可以发现这里的init方法中传递的就是一个WindowManagerService的实例
            }
        }, 0);
    }
...

那么在PowerAction的onPress方法中调用的mWindowManagerFuncs.shutdown方法,实际上调用的就是WindowManagerService的shutdown方法。

// Called by window manager policy.  Not exposed externally.
    @Override
    public void shutdown(boolean confirm) {
        ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
    }

很简单地直接调用了ShutdownThread的shutdown方法。表明真正执行关机线程的是ShutdownThread.shutdown。

frameworks\base\services\core\java\com\android\server\power\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.
     * @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); //具体关机操作
    }

设置ShutdownThread的全局属性后将具体的操作下发到了shutdownInner方法中。

static void shutdownInner(final Context context, boolean confirm) {
        // 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); //获取长按资源id 
        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) { //是否需要确认关机
            final CloseDialogReceiver closer = new CloseDialogReceiver(context);
            if (sConfirmDialog != null) {
                sConfirmDialog.dismiss();
            }
            bConfirmForAnimation = confirm;
            Log.d(TAG, "PowerOff dialog doesn't exist. Create it first");
            sConfirmDialog = new AlertDialog.Builder(context) //需要再次确认关机, 创建dialog
                .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) {
                        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);
        }
    }

对于参数context和confirm,context用来用来显示关机进程的对话,confirm如果是true表示关机之前需要显示确认关机的对话框。
longPressBehavior和resourceId是用来记录一些标志。在咱们的源码中,confirm为false,则直接执行beginShutdownSequence(),开始进入关机流程。

private static void beginShutdownSequence(Context context) {
        synchronized (sIsStartedGuard) { //确保单一进程操作
            if (sIsStarted) {
                Log.d(TAG, "Shutdown sequence already running, returning.");
                return;
            }
            sIsStarted = true;
        }


        // Throw up a system dialog to indicate the device is rebooting / shutting down.
        /* 360OS begin, use no 360os dialog style */
        //ProgressDialog pd = new ProgressDialog(context);
        ProgressDialog pd = new ProgressDialog(context, 0, true); //初始化一个Process的dialog,用于显示关机进度
        /* 360OS end */


        // Path 1: Reboot to recovery for update
        //   Condition: mReason == 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)
        if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) { //重启进入recovery模式进行系统升级
            // 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 {
                pd.setIndeterminate(true);
                pd.setMessage(context.getText(
                            com.android.internal.R.string.reboot_to_update_reboot));
            }
        } else if (PowerManager.REBOOT_RECOVERY.equals(mReason)) { //重启进入recovery模式进行恢复出厂设置
            // 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 { //正常关机
            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);


//关机的ProgressDialog各项参数设置完成,进入启动关机线程
        // start the thread that initiates shutdown
        sInstance.mContext = context; //sInstance是ShutdownThread静态类实例,context继续用来显示关机进程的对话框
        sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        sInstance.mHandler = new Handler() {
        };


        beginAnimationTime = 0; //开始设置关机动画
        boolean mShutOffAnimation = configShutdownAnimation(context);
        int screenTurnOffTime = getScreenTurnOffTime(context);
        synchronized (mEnableAnimatingSync) {
            if (mEnableAnimating) {
                if (mShutOffAnimation) { //显示关机动画
                    Log.d(TAG, "mIBootAnim.isCustBootAnim() is true");
                    bootanimCust(context);
                } else { //不显示关机动画
                    pd.show(); //那么展示关机ProgressDialog


                    sInstance.mProgressDialog = pd;
                }
                sInstance.mHandler.postDelayed(mDelayDim, screenTurnOffTime);
            }
        }


        // make sure we never fall asleep again
        sInstance.mCpuWakeLock = null; //防止手机进入休眠状态
        try {
            sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
                    PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu"); //PARTIAL_WAKE_LOCK:保持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"); //FULL_WAKE_LOCK:保持CPU运转,保持屏幕高亮显示,键盘灯也保持亮度
                sInstance.mScreenWakeLock.setReferenceCounted(false);
                sInstance.mScreenWakeLock.acquire();
            } catch (SecurityException e) {
                Log.w(TAG, "No permission to acquire wake lock", e);
                sInstance.mScreenWakeLock = null;
            }
        }


        if (sInstance.getState() != Thread.State.NEW || sInstance.isAlive()) { //启动关机线程异常的处理
            if (sInstance.mShutdownFlow == IPO_SHUTDOWN_FLOW) {
                Log.d(TAG, "ShutdownThread exists already");
                checkShutdownFlow();
                synchronized (mShutdownThreadSync) {
                    mShutdownThreadSync.notify();
                }
            } else {
                Log.e(TAG, "Thread state is not normal! froce to shutdown!");
                delayForPlayAnimation();
                //unmout data/cache partitions while performing shutdown
                sInstance.mPowerManager.goToSleep(SystemClock.uptimeMillis(),
                        PowerManager.GO_TO_SLEEP_REASON_SHUTDOWN, 0);
                PowerManagerService.lowLevelShutdown(mReason);
            }
        } else {
            sInstance.start(); //启动shutdown线程
        }
    }

参数context用来显示关机进程的对话框;sInstance是ShutdownThread静态类实例,也是this thread的实例;ProgressDialog pd用来启动一个系统进度对话框,pd的成员函数setTitle()、setMessage()、setIndeterminate()、setCancelable()会根据context内容对对话框属性进行设置,使用show()来显示;通过sInstance.mCpuWakeLock来获得cpuwakelock,使系统不会休眠;通过sInstance.mScreenWakeLock获得screenwakelock使屏幕长亮;最后启动shutdown线程sInstance.start()。

/**
     * 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() { //关机预处理
        checkShutdownFlow();
        while (mShutdownFlow == IPO_SHUTDOWN_FLOW) {
            mShutdownManager.saveStates(mContext);
            mShutdownManager.enterShutdown(mContext);
            switchToLauncher();
            running(); //正式启动关机线程
        }
        if (mShutdownFlow != IPO_SHUTDOWN_FLOW) {
            mShutdownManager.enterShutdown(mContext);
            switchToLauncher();
            running(); //正式启动关机线程
        }
    }


    private void running() {
        command = SystemProperties.get("sys.ipo.pwrdncap");


        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(); //接收关机广播,不允许app取消该线程
            }
        };


        /*
         * 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); //设置系统属性值,以防止我们进入实际的硬件restart之前system_server reboots
        }


        /*
         * If we are rebooting into safe mode, write a system property
         * indicating so.
         */
        if (mRebootSafeMode) {
            SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1"); //设置系统属性值,表明是否rebooting进入到safe mode
}


...

        if (mShutdownFlow != IPO_SHUTDOWN_FLOW) {
            Log.i(TAG, "Shutting down activity manager...");


            final IActivityManager am =
                ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
            if (am != null) {
                try {
                    am.shutdown(MAX_BROADCAST_TIME); //最大广播时间内(10s)关闭ActivityManager
                } catch (RemoteException e) {
                }
            }
            if (mRebootHasProgressBar) {
                sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
            }
        }


        Log.i(TAG, "Shutting down package manager...");


        final PackageManagerService pm = (PackageManagerService)
            ServiceManager.getService("package");
        if (pm != null) {
            pm.shutdown(); //关闭PackageManager
        }
        if (mRebootHasProgressBar) {
            sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
        }


        // Shutdown radios.
        Log.i(TAG, "Shutting down radios...");
        shutdownRadios(MAX_RADIO_WAIT_TIME); //最大收音等待时间(12s)内关闭收音机
        if (mRebootHasProgressBar) {
            sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
        }


        if ((mShutdownFlow == IPO_SHUTDOWN_FLOW) && (command.equals("1") || command.equals("3"))) {
            Log.i(TAG, "bypass MountService!");
        } else {
            // Shutdown MountService to ensure media is in a safe state
            IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
                public void onShutDownComplete(int statusCode) throws RemoteException {
                    Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
                    if (statusCode < 0) {
                        mShutdownFlow = NORMAL_SHUTDOWN_FLOW;
                    }
                    actionDone();
                }
            };


            Log.i(TAG, "Shutting down MountService");


            // Set initial variables and time out time.
            mActionDone = false;
            final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
            synchronized (mActionDoneSync) {
                try {
                    final IMountService mount = IMountService.Stub.asInterface(
                            ServiceManager.checkService("mount"));
                    if (mount != null) {
                        mount.shutdown(observer); //关闭MountService
                    } else {
                        Log.w(TAG, "MountService unavailable for shutdown");
                    }
                } catch (Exception e) {
                    Log.e(TAG, "Exception during MountService shutdown", e);
                }
                while (!mActionDone) {
                    long delay = endShutTime - SystemClock.elapsedRealtime();
                    if (delay <= 0) {
                        Log.w(TAG, "Shutdown wait timed out");
                        if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {
                            Log.d(TAG, changeToNormalMessage + ": MountService");
                            mShutdownFlow = NORMAL_SHUTDOWN_FLOW;
                        }
                        break;
                    } else if (mRebootHasProgressBar) {
                        int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
                            (MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
                            MAX_SHUTDOWN_WAIT_TIME);
                        status += RADIO_STOP_PERCENT;
                        sInstance.setRebootProgress(status, null);
                    }
                    try {
                        mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
                    } catch (InterruptedException e) {
                    }
                }
            }
            Log.i(TAG, "MountService shut done...");
        }

...
        rebootOrShutdown(mContext, mReboot, mReason); //最终执行重启或关机的函数
    }

在关机过程中发送完关机广播后,依次关闭ActivityManager Service、PackageManager Service、Radio、MountService。最后执行的shutdown流程的函数rebootOrShutdown()。

/**
     * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
     * or {@link #shutdown(Context, 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) {
        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); //调用底层方法关闭电源
    }

二、
PowerManagerService.lowLevelShutdown函数调用后开始进入JNI层和kernel层。

frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java:

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

这是一个通往下层JNI的函数。

frameworks\base\core\java\android\os\SystemProperties.java:

/**
     * Set the value for the given key.
     * @throws IllegalArgumentException if the key exceeds 32 characters
     * @throws IllegalArgumentException if the value exceeds 92 characters
     */
    public static void set(String key, String val) {
        if (key.length() > PROP_NAME_MAX) {
            throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
        }
        if (val != null && val.length() > PROP_VALUE_MAX) {
            throw new IllegalArgumentException("val.length > " +
                PROP_VALUE_MAX);
        }
        native_set(key, val); //底层方法
    }

判断参数,抛出异常后,native_set方法实际操作通过JNI调用底层cpp文件对应的接口SystemProperties_set。

frameworks\base\core\jni\android_os_SystemProperties.cpp:

static void SystemProperties_set(JNIEnv *env, jobject clazz,
                                      jstring keyJ, jstring valJ)
{
int err;
const char* key;
const char* val;


if (keyJ == NULL) {
jniThrowNullPointerException(env, "key must not be null.");
return ;
}
key = env->GetStringUTFChars(keyJ, NULL);


if (valJ == NULL) {
val = "";       /* NULL pointer not allowed here */
} else {
val = env->GetStringUTFChars(valJ, NULL);
}


err = property_set(key, val); //调用函数int property_set


env->ReleaseStringUTFChars(keyJ, key);


if (valJ != NULL) {
env->ReleaseStringUTFChars(valJ, val);
}


if (err < 0) {
ALOGE("setproperty key=%s value=%s err=%d\n", key, val, err);
jniThrowException(env, "java/lang/RuntimeException",
"failed to set system property");
}
}

先检查传入参数的合法性使用err = property_set(key, val),根据err的值输出log。

system\core\init\property_service.cpp:

int property_set(const char* name, const char* value) {
int rc = property_set_impl(name, value);
if (rc == -1) {
ERROR("property_set(\"%s\", \"%s\") failed\n", name, value);
}
return rc;
}

static int property_set_impl(const char* name, const char* value) {
size_t namelen = strlen(name);
size_t valuelen = strlen(value);


if (!is_legal_property_name(name, namelen)) return -1;
if (valuelen >= PROP_VALUE_MAX) return -1;


if (strcmp("selinux.reload_policy", name) == 0 && strcmp("1", value) == 0) {
if (selinux_reload_policy() != 0) {
ERROR("Failed to reload policy\n");
}
} else if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
if (restorecon_recursive(value) != 0) {
ERROR("Failed to restorecon_recursive %s\n", value);
}
}


prop_info* pi = (prop_info*) __system_property_find(name); //找到对应name的系统属性字段


if(pi != 0) {
/* ro.* properties may NEVER be modified once set */
if(!strncmp(name, "ro.", 3)) {
#ifdef MTK_INIT
ERROR("PropSet Error:[%s:%s]  ro.* properties may NEVER be modified once set\n", name, value);
#endif
return -1;
}
__system_property_update(pi, value, valuelen); //更新系统属性字段
} else {
int rc = __system_property_add(name, namelen, value, valuelen); //添加系统属性字段
if (rc < 0) {
#ifdef MTK_INIT
ERROR("Failed to set '%s'='%s'\n", name, value);
#endif
return rc;
}
}
/* If name starts with "net." treat as a DNS property. */
if (strncmp("net.", name, strlen("net.")) == 0)  {
if (strcmp("net.change", name) == 0) {
#ifdef MTK_INIT
INFO("PropSet [%s:%s] Done\n", name, value);
#endif
return 0;
}
/*
* The 'net.change' property is a special property used track when any
* 'net.*' property name is updated. It is _ONLY_ updated here. Its value
* contains the last updated 'net.*' property.
*/
property_set("net.change", name);
} else if (persistent_properties_loaded &&
strncmp("persist.", name, strlen("persist.")) == 0) {
/*
* Don't write properties to disk until after we have read all default properties
* to prevent them from being overwritten by default values.
*/
write_persistent_property(name, value);
}
property_changed(name, value); //改变属性值
#ifdef MTK_INIT
INFO("PropSet [%s:%s] Done\n", name, value);
#endif
return 0;
}

使用了多个函数进行判断、预处理。最后调用函数改变系统属性字段值。

system\core\init\init.cpp:

void property_changed(const char *name, const char *value)
{
if (property_triggers_enabled)
ActionManager::GetInstance().QueuePropertyTrigger(name, value);
}

改变系统属性字段值,添加到触发器。

可以发现,系统通过Android Property机制来进行关机操作。关机操作相关的属性被组织成简单的键值对,通过修改属性值,相关的触发器来触发相应的操作。通过adb连接手机到终端,实际验证输入命令adb shell,然后设置属性值,setprop sys.powerctl shutdown,观察发现手机完成了关机操作。

你可能感兴趣的:(笔记保存)