android 5.1 非STR待机流程

android在长按Power键(手机或pad)或按下电源键(电视)会进入待机状态,下面分析一下非STR待机流程。

待机分STR和非STR待机。

STR待机是为了实现快速开关机,提高开机速度。android自身支持STR,OEM可以根据自身需要进行深度定制。STR待机时,PM芯片仍然供电,其他断电,当STR开机时,从PM芯片唤醒,回复到STR待机前状态,从而提高开机速度。

非STR待机即正常待机,待机后会彻底断电,这里只分析android层的行为。

1 PhoneWindowManager处理逻辑

按键在给到WindowManagerService之前,会先给到PhoneWindowManager进行处理。

 /** {@inheritDoc} */
    @Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
    //KeyEvent入队
    ...
     case KeyEvent.KEYCODE_POWER: {
	Log.d(TAG,"KEYCODE_POWER.....");
         result &= ~ACTION_PASS_TO_USER;
         isWakeKey = false; // wake-up will be handled separately
          if (down) {
               interceptPowerKeyDown(event, interactive);
           } else {
               interceptPowerKeyUp(event, interactive, canceled);
            }
           break;

在key Down时,执行interceptPowerKeyDown逻辑,这段逻辑会处理正常待机流程。 在key Up时,执行interceptPowerKeyUp逻辑,这段逻辑出来STR待机流程。

  private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
        // Hold a wake lock until the power key is released.
        if (!mPowerKeyWakeLock.isHeld()) {
            //获取wakeLock
            mPowerKeyWakeLock.acquire();
        }
     ...
     // Latch power key state to detect screenshot chord.
        if (interactive && !mScreenshotChordPowerKeyTriggered
                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
            mScreenshotChordPowerKeyTriggered = true;
            mScreenshotChordPowerKeyTime = event.getDownTime();
            //截图,STR和非STR待机都会执行截图,截图为了在待机时画面看起来很和谐
            interceptScreenshotChord();
        }
     ...
      // 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()) {  //如果不是LONG_PRESS_POWER_NOTHING
                    if (enable_str == false) {  //非STR
                        if (mShortPressOnPowerBehavior < 0) {  //如果等于0,重新赋值
                            mShortPressOnPowerBehavior = mContext.getResources().getInteger(
                                    com.android.internal.R.integer.config_shortPressOnPowerBehavior);
                        }
                       //发送MSG_POWER_LONG_PRESS,处理待机事件
                        Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
                        msg.setAsynchronous(true);
                        //是否延迟待机
                        mHandler.sendMessageDelayed(msg,
                                (mShortPressOnPowerBehavior == SHORT_PRESS_POWER_SHUT_DOWN) ?
                                0 : ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
                    }

config_shortPressOnPowerBehavior默认值是1,在frameworks\base\core\res\res\values\config.xml中有定义:

    <!-- Control the behavior when the user short presses the power button.
            0 - Nothing
            1 - Go to sleep (doze)
            2 - Really go to sleep (don't doze)
            3 - Really go to sleep and go home (don't doze)
    -->
    <integer name="config_shortPressOnPowerBehavior">1</integer>

1表示会弹出一个系统Dialog提示用户选择重启还是关机。 2表示直接待机,不会提示用户。 3看字面意思是会先回到home再去待机,也不会给用户提示。    case MSG_POWER_LONG_PRESS:

                    powerLongPress();

对于handler消息的处理会call powerLongPress函数,具体实现如下:

 private void powerLongPress() {
        final int behavior = getResolvedLongPressOnPowerBehavior();
        switch (behavior) {
        case LONG_PRESS_POWER_NOTHING:
            break;
        case LONG_PRESS_POWER_GLOBAL_ACTIONS:
            mPowerKeyHandled = true;
            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
                performAuditoryFeedbackForAccessibilityIfNeed();
            }
            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;
        }
    }

在我现在的平台,在overlay的config.xml配置config_shortPressOnPowerBehavior等于2,即会直接待机,不会走showGlobalActionsInternal。

2 WindowManagerService处理逻辑

WindowManagerService有实现WindowManagerPolicy.WindowManagerFuncs函数,所以在PhoneWindowManager中调用mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);时会call到WindowManagerService的shutdown函数。

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

看起来WindowManagerService只是一个封装,最后call到ShutdownThread的shutdown函数。 这里的confirm参数根据resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF来看是等于true.

3 ShutdownThread处理逻辑

ShutDownThread是一个Thread,对于shutdown函数的实现如下:

 /**
     * 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 confirm true if user confirmation is needed before shutting down.
     */
    public static void shutdown(final Context context, boolean confirm) {
        mReboot = false;
        mRebootSafeMode = false;
        shutdownInner(context, confirm);
    }

看函数的解释是必须要在有Looper并且可以显示UI的thread去call这个函数。

    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);
        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();
            }
            sConfirmDialog = new AlertDialog.Builder(context)
                    .setTitle(mRebootSafeMode
                            ? com.android.internal.R.string.reboot_safemode_title
                            : com.android.internal.R.string.power_off)
                    .setMessage(resourceId)
                    .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            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);
        }
    }

根据上面提到的confirm参数是true,那么会走上面的逻辑,但是上面的逻辑会显示dialog,在我的平台,待机是不会显示dialog的,需要加打印确定下这个值是否为true. 在confirm为false或点击Dialog的OK按钮,会调用beginShutdownSequence函数,开始进入待机时序。

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

 private static final ShutdownThread sInstance = new ShutdownThread(); 调用ShutdownThread的start函数,执行run函数(线程):

     * 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") + (mRebootReason != null ? mRebootReason : "");
            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...");
        
        // First send the high-level shut down broadcast.
        mActionDone = false;
        Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        mContext.sendOrderedBroadcastAsUser(intent,
                UserHandle.ALL, null, br, mHandler, 0, null, null);
        
        final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
        synchronized (mActionDoneSync) {
            while (!mActionDone) {
                long delay = endTime - SystemClock.elapsedRealtime();
                if (delay <= 0) {
                    Log.w(TAG, "Shutdown broadcast timed out");
                    break;
                }
                try {
                    mActionDoneSync.wait(delay);
                } catch (InterruptedException e) {
                }
            }
        }
        
        Log.i(TAG, "Shutting down activity manager...");
        
        final IActivityManager am =
            ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
        if (am != null) {
            try {
                am.shutdown(MAX_BROADCAST_TIME);
            } catch (RemoteException e) {
            }
        }

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

        final PackageManagerService pm = (PackageManagerService)
            ServiceManager.getService("package");
        if (pm != null) {
            pm.shutdown();
        }

        // Shutdown radios.
        shutdownRadios(MAX_RADIO_WAIT_TIME);

        // 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");
                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);
                } 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");
                    break;
                }
                try {
                    mActionDoneSync.wait(delay);
                } catch (InterruptedException e) {
                }
            }
        }

        rebootOrShutdown(mReboot, mRebootReason);
    }

主要的逻辑: 1)发送待机广播  Intent intent = new Intent(Intent.ACTION_SHUTDOWN);

intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

mContext.sendOrderedBroadcastAsUser(intent,UserHandle.ALL, null, br, mHandler, 0, null, null); 这里感觉不应该用Order的方式,否则会导致有些app无法收到SHUTDOWN广播。 2)ActivityManagerService shutdown 3)PackageManagerService shutdown 4)Shutdown radios

  /**
     * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
     * or {@link #shutdown(Context, boolean)} instead.
     *
     * @param reboot true to reboot or false to shutdown
     * @param reason reason for reboot
     */
    public static void rebootOrShutdown(boolean reboot, String reason) {
        if (reboot) {
            Log.i(TAG, "Rebooting, reason: " + reason);
            PowerManagerService.lowLevelReboot(reason);
            Log.e(TAG, "Reboot failed, will attempt shutdown instead");
        } else if (SHUTDOWN_VIBRATE_MS > 0) {
            // vibrate before shutting down
            Vibrator vibrator = new SystemVibrator();
            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();
    }

如果是重启,会call到PowerManagerService.lowLevelReboot(reason); 这里是关机,会call到PowerManagerService.lowLevelShutdown();

4 PowerManagerService处理逻辑

PowerManagerService的实现很简单,直接call到JNI层。

 /**
     * Low-level function turn the device off immediately, without trying
     * to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown.
     */
    public static void lowLevelShutdown() {
        nativeShutdown();
    }

5 PowerManagerService JNI层处理逻辑

PowerManagerService JNI对应的文件: com_android_server_power_PowerManagerService.cpp

static void nativeShutdown(JNIEnv *env, jclass clazz) {
    if (gPowerModule && gPowerModule->shutdown) {
        gPowerModule->shutdown(gPowerModule);
    }
}

直接call到Power HAL层

6 Power HAL层处理逻辑

Power HAL层对应的文件power.cpp struct power_module HAL_MODULE_INFO_SYM = {

.. .shutdown = power_shutdown

}  power_shutdown函数实现call到我司中间层的enterSleepMode函数(基于保密原则,无法公开代码)

Android部分待机流程分析完毕,1-3步是android标准流程,4-6步是我司客制化部分,但是流程应该都是大同小异。

    原文作者:zhudaozhuan
    原文地址: https://blog.csdn.net/zhudaozhuan/article/details/50904752
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞