Android原生待机流程frameworks层分析

之前做平台项目的时候,关于待机这一块真的是出现了很多问题,因为我们开发智能电视的待机流程和Android原生待机又有一些不同,我们在Android原生的基础上增加了一些我们自己的东西,比如待机前会给出警示等。自己没事的时候也研究过Android原生的待机和我们自己的待机流程,最近又有负责SRT待机这一块的一个同事做过一次技术分享,然后就趁五一放假有时间好好整理一下。

PS:以下分析都是基于Android4.3的

Android原生待机流程

Android原生待机流程如下图所示:

用户在长按Android的电源键的时候会在Android的frameworks层被捕获,具体文件路径是

1
frameworks\base\policy\src\com\android\internal\policy\impl

中的PhoneWindowManager.java进行处理,当按下待机键时会在PhoneWindowManager中的interceptKeyBeforeQueueing方法中将PowerKey拦下,然后进行判断是一次动作还是长按,是长按的话就会触发mPowerLongPress这个线程,我们来看一下这个线程的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private final Runnable mPowerLongPress = new Runnable() {
@Override
public void run() {
// The context isn't read
if (mLongPressOnPowerBehavior < 0) {
mLongPressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);
}
int resolvedBehavior = mLongPressOnPowerBehavior;
if (FactoryTest.isLongPressOnPowerOffEnabled()) {
resolvedBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
}

switch (resolvedBehavior) {
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
if(!performHapticFeedbackLw(null,HapticFeedbackConstants.LONG_PRESS,false)) {
performAuditoryFeedbackForAccessibilityIfNeed();
}
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
showGlobalActionsDialog();
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(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF);
break;
}
}
};

从开头这句int mLongPressOnPowerBehavior = -1;我们可以知道mLongPressOnPowerBehavior最开始是被初始化成-1的。所以最开的if条件成立,然后mLongPressOnPowerBehavior的值会从config_longPressOnPowerBehavior配置中读取,然后赋值给resolvedBehavior

判断FactoryTest中长按关机是否设置了,如果设置了就将LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM复制给resolvedBehavior,这种模式下不会弹出提示对话框就直接关机。

然后判断resolvedBehavior的值,根据其值来决定下一步执行什么动作。正常情况下改值等于LONG_PRESS_POWER_GLOBAL_ACTIONS=1,这是正常关机的流程,先设置mPowerKeyHandled值为true,告诉系统待机键已经处理了。然后开始发送消息告诉系统可以弹出提示对话框让用户选择下一步操作了。最后showGlobalActionsDialog()就会show出对话框
我们可以简单看一下showGlobalActionDialog()的代码:

1
2
3
4
5
6
7
8
9
10
11
12
void showGlobalActionsDialog() {
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
final boolean keyguardShowing = keyguardIsShowingTq();
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.
mKeyguardMediator.userActivity();
}
}

首先会实例化一个GlobalActions对象mGlobalActions,通过查看源代码可以看到GlobalActions是实现了接口DialogInterface.OnDismissListener和DialogInterface.OnClickListener的一个普通类,里面定义的是关于对话框的一些方法和属性。然后showDialog(),最后根据keyguardShowing的值,该值代表是否在锁屏状态,决定是否要调用userActivity(),该方法是保持屏幕常亮,接下来看一下showDialog这个方法的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 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();
}
}

注释已经写的很清楚了,如果该对话框存在就直接show出来,否则调用handleShow(),我们可以再看一下handleShow()的源代码:

1
2
3
4
5
6
7
8
9
10
11
12
private void handleShow() {
awakenIfNecessary();
mDialog = createDialog();
prepareDialog();

WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
attrs.setTitle("GlobalActions");
mDialog.getWindow().setAttributes(attrs);
mDialog.show();
mDialog.getWindow().getDecorView().
setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
}

看到这一句mDialog=createDialog(),我们就应该知道是创建对话框了,createDialog()方法主要就是创建提示对话框,将提示框上需要显示的选项显示出来,因为该方法太长,就不贴出来了,有兴趣的可以看源码,路径是:

1
frameworks\base\policy\src\com\android\internal\policy\impl\GlobalActions.java

我们可以看一下关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// first: power off
mItems.add(new SinglePressAction(
com.android.internal.R.drawable.ic_lock_power_off,
R.string.global_action_power_off) {
public void onPress() {
// shutdown by making sure radio and power are handled accordingly.
mWindowManagerFuncs.shutdown(true);
}

public boolean onLongPress() {
mWindowManagerFuncs.rebootSafeMode(true);
return true;
}

public boolean showDuringKeyguard() {
return true;
}

public boolean showBeforeProvisioning() {
return true;
}
});

从这段代码中可以看出,提示框上会添加Power off试图,点击的话就会调用shutdown,顺着分析下去,会在

1
/frameworks/base/core/java/android/view/WindowManagerPolicy.java

中找到public void shutdown(boolean confirm),但是只有声明,实现并不在这里,grep搜索一下会发现实现是在

1
/frameworks/base/services/java/com/android/server/wm/WindowManagerService.java

中实现的

在这里就会调用关机线程,关机线程在

1
\frameworks\base\services\java\com\android\server\power\ShutdownThread.java

中,线程中会调用PowerManagerService.lowLevelShutdown(),再下来就是JNI调用C++层了
所以梳理一下,整个流程图如下所示:

上层的分析就到这里了,这是Android原生的待机流程,下一篇我写一下我们智能电视的SRT待机流程