1. 关联唤醒机制
关联唤醒中的原理在于在应用启动的各种通道中进行拦截
- 在ActivityStarter 进行 start-activity 监听,judgeAppLaunchAllowedInternal 判断是否拦截
- 在ActivityManagerService 进行 contentprovider 监听,judgeAppLaunchAllowedInternal 判断是否拦截
- 在BroadcastQueue 进行 send-broadcast,judgeAppLaunchAllowedInternal 判断是否拦截
- 在ActiveServices 进行 start-service 和 bind-service监听,judgeAppLaunchAllowedInternal 判断是否拦截
2. judgeAppLaunchAllowedInternal 函数
- vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/power/BackgroundCleanHelper.java
该函数主要进行是否拦截的判断,这里的判断条件主要根据activty\contentprovid\broadcast\servie\UID范围\进程状态\设置界面的黑白名单\用户是否触摸事件\特殊场景(输入法、壁纸服务、小部件、语音输入、CTS场景等)\用户主动点击行为,等等多个维度进行条件判断,决定是否运行进程启动。
/*
* Third app can not self started:
* 1. not allow system broadcast from "systemserver" or "com.android.systemui"
* 2. not allow start service from ""com.android.shell"
* 3. not allow background app to launch other third party app
* 4. not allow self started third party app to start other third party app
* 5. not allow third party app to start other third party app during standby
*
* Note: This api is call from AMS in other threads and may be in variable calling context
* SO BE CAREFULL : avoid call other system API that may hold lock. Otherwise, a deadlock may HAPPEN
*/
boolean judgeAppLaunchAllowedInternal(Intent intent, String targetApp, int targetUid,
int callerUid, String callerApp, String reason) {
// 总开关是否关闭
// if this function is disabled, just return true
if (!mEnabled) return true;
if (DEBUG_MORE) Slog.d(TAG,"judgeAppLaunchAllowed : "+targetApp+"(uid:" + targetUid
+ "), callingPackage = "+callerApp+"(uid:" + callerUid + "), reason = "+reason);
if (DEBUG_MORE && intent != null) Slog.d(TAG,"judgeAppLaunchAllowed : intent action:" + intent);
// 目标进程是否为未知
if (targetApp == null) return true;
// 是否允许 start-service 类型启动
if (handleStartServiceStartAction(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
return true;
}
// 是否允许 bind-service 类型启动
if (handleBindServiceStartAction(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
return true;
}
// 是否允许contentprovider 类型启动
if (handleContentProviderStartAction(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
return true;
}
// 是否允许输入法类型启动
if (isLaunchingIMEApp(intent, targetApp, targetUid, callerApp, reason)) {
return true;
}
// 是否允许 send-broadcast 类型启动
if (handleBroadcastAction(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
return true;
}
// 是否允许语音识别
//handle speech recognition
if (isRecognizerIntent(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
return true;
}
// 是否允许 CTS 或者adb shell 测试运行
// allow cts app to start any other app
// allow autotest app
if (Util.isCts(callerApp) || isAutoTest(callerUid, callerApp, targetApp)) {
return true;
}
// check deny for ultra saving mode
//if (denyBecauseOfUltraSavingMode(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
// return false;
//}
// 获取target进程 UID
int targetUserId = UserHandle.getUserId(targetUid);
// 获取callUser进程的 UID
int callUserId = UserHandle.getUserId(callerUid);
// 获取 caller 进程信息
AppState callerAppState = mAppStateInfoCollector.getAppState(callerApp, callUserId);
// 获取 target 进程信息
AppState targetAppState = mAppStateInfoCollector.getAppState(targetApp, targetUserId);
// if target app already exist
/*if (targetAppState != null
&& targetAppState.mProcState < ActivityManager.PROCESS_STATE_CACHED_EMPTY
&& targetAppState.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT) {*/
// 进程已经启动
if (isAlreadyStarted(targetAppState)) {
if (DEBUG_MORE) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": already started!!"
+ " (ProcState:" + Util.ProcState2Str(targetAppState.mProcState)
+ " mState:" + Util.AppState2Str(targetAppState.mState)
+ ")");
return true;
}
// check system app
// allow to launch system app
int launchState = checkLaunchStateByPreset(intent, targetApp, targetUid, callerApp, callerUid, reason);
if (launchState == LAUNCH_STATE_ALLOW)
// 允许启动
return true;
else if (launchState == LAUNCH_STATE_DENY)
// 禁止启动
return false;
// check user setting for third-party app
// 检查预设值白名单和省电管理界面白名单进行判断是否需要允许启动,再次进行launchState设置
launchState = checkLaunchStateByUserSetting(intent, targetApp, targetUid, callerApp, callerUid, reason);
if (DEBUG_MORE) Slog.d(TAG, "launchState: " + launchState);
if (launchState == LAUNCH_STATE_ALLOW)
return true;
else if (launchState == LAUNCH_STATE_DENY)
return false;
// 待机模式下禁止待机动态的黑名单应用启动
// not allow third party app that has been force stopped during standby
// to be started again
if (mStandbyStartTime > 0 && isForceStoppedAppDuringStandby(targetApp, targetUid)) {
if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed (has been force stopped)!!");
return false;
}
// 禁止系统广播启动第三方应用
// not allow system broadcast to launch third party app
if ((callerAppState == null ||(callerApp != null && callerApp.equals("android")))
&& REASON_BROADCAST.equals(reason)) {
if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!!");
return false;
}
// 禁止"system ui"广播启动第三方应用
// not allow "com.android.systemui" broadcast to launch third party app
if (callerApp != null && callerApp.equals("com.android.systemui")
&& REASON_BROADCAST.equals(reason)) {
if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!!");
return false;
}
// allow app to launch itself
// 允许应用自启动
if (targetApp.equals(callerApp)) {
return true;
}
// not allow non-top app to launch other app, except launched by UserActivity
// 允许进程本身启动自有activity,但不允许启动其他应用
// 条件 非用户主动点击
if (!launchedByUserActivity(intent, targetApp, targetUid, callerApp, callerUid, reason, true)) {
if (DEBUG) {
Slog.d(TAG,"Start Proc : "+targetApp
+", callingPackage = "+callerApp
+ " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
+"), reason = "+reason
+ ": non-UserActivity denyed!!");
}
return false;
}
// not allow background app to launch other third party app
// 不允许后台应用关联唤醒其他应用
// 1. caller 不用空
// 2. caller 状态为非前台进程,mProcState 数值越大进程重要度越低
// 3. 启动类型不为 start-acitivty
if (callerAppState != null && callerAppState.mProcState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
&& !REASON_START_ACTIVITY.equals(reason)) {
if (DEBUG) {
Slog.d(TAG,"Start Proc : "+targetApp
+", callingPackage = "+callerApp
+ " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
+"), reason = "+reason
+ ": denyed!!");
}
return false;
}
// 不允许第三方应用之间进行关联唤醒
// not allow self started third party app to start other third party app
// 1. caller 状态不为空
// 2. caller 启动次数为0
// 3. 非系统应用
// 4. 启动类型非start-activity
if (callerAppState != null && callerAppState.mLaunchCount == 0 && !isSystemApp(callerAppState)
&& !REASON_START_ACTIVITY.equals(reason)) {
if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!!");
return false;
}
// 不允许长时间运行的后台应用唤醒其他应用
// not allow long idle third party app to start other third party app
// 1. caller 状态不为空
// 2. caller 非第三应用
// 3. caller 不为前台进程属性
// 4. 启动类型非start-activity
if (callerAppState != null && !isSystemApp(callerAppState)
&& callerAppState.mState != Event.MOVE_TO_FOREGROUND
&& callerAppState.mProcState != ActivityManager.PROCESS_STATE_TOP
&& !REASON_START_ACTIVITY.equals(reason)) {
// 当前流逝时刻
long nowELAPSED = SystemClock.elapsedRealtime();
// 待机场景持续时长
long idleDuration = 0;
// 待机场景持续时长 = 当前流逝时刻 - caller 最近一次运行时长
idleDuration = (callerAppState.mLastTimeUsed > 0 ? (nowELAPSED -callerAppState.mLastTimeUsed) : -1);
// 第三方应用在后台运行超过 DENY_START_APP_THRESHOLD,则不允许第三方进程
// 即不允许长时间运行的后台应用唤醒其他应用
if (idleDuration > DENY_START_APP_THRESHOLD) {
if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!! long idle");
return false;
}
}
// 待机模式下,不允许第三方应用进行相互关联唤醒
// not allow third party app to start other third party app during standby
if (mStandbyStartTime > 0
&& !REASON_START_ACTIVITY.equals(reason)) {
if (DEBUG) {
Slog.d(TAG,"Start Proc : "+targetApp
+", callingPackage = "+callerApp
+ " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
+"), reason = "+reason
+ ": denyed during standby!!");
}
return false;
}
return true;
}
2.1 handleStartServiceStartAction
是否允许 start-service 类型启动
private static final String REASON_START_SERVICE = "start-service";
// 是否允许 start-service 类型启动
// return true: for should be allow to be started
// false: for others
private boolean handleStartServiceStartAction(Intent intent, String targetApp, int targetUid,
String callerApp, int callerUid, String reason) {
// 是否为 start-service 类型启动
if (!REASON_START_SERVICE.equals(reason)) return false;
// 是否在安装列表中
if (mInstalledServiceList.contains(targetApp)
// 是否可以被其他应用启动
&& autoLaunchByOtherApp(targetApp, targetUid, callerApp, callerUid, reason)) {
if (DEBUG) Slog.d(TAG, "start installed service :" + targetApp + " from " + callerApp);
return true;
}
return false;
}
2.1.0 是否可被关联启动 autoLaunchByOtherApp
判断这是系统启动还是被第三方应用关联启动,主要通过UID进行判断
// 判断这是系统启动还是被第三方应用关联启动,主要通过UID进行判断
// return true, if app is start by system broadcast
private boolean autoLaunchByOtherApp(String targetApp, int targetUid,
String callerApp, int callerUid, String reason) {
// 启动发起方是否为null或android或systemui,如果是该条件,则绝对是系统进行唤醒
if (callerApp == null
||callerApp.equals("android")
|| callerApp.equals("com.android.systemui"))
return false;
AppState callerAppState = mAppStateInfoCollector.getAppState(callerApp, UserHandle.getUserId(callerUid));
// 唤醒者是否为系统进程调用
if (callerAppState != null && callerAppState.mUid < Process.FIRST_APPLICATION_UID)
return false;
return true;
}
2.2 handleBindServiceStartAction
是否允许 bind-service 务类型启动
private static final String REASON_BIND_SERVICE = "bind-service";
// return true: for should be allow to be started
// false: for others
private boolean handleBindServiceStartAction(Intent intent, String targetApp, int targetUid,
String callerApp, int callerUid, String reason) {
// 是否为 bind-service 类型启动
if (!REASON_BIND_SERVICE.equals(reason)) return false;
// 是否为壁纸服务
// check start wallpaper service
if (intent != null && WallpaperService.SERVICE_INTERFACE.equals(intent.getAction())) {
// save the defalut wallpaper service
if ("android".equals(callerApp)) mDefaultWallpaperService = targetApp;
if (DEBUG) Slog.d(TAG, "start wallpaper service, allowed");
return true;
}
// 是否为可用模拟辅助服务
if ("android".equals(callerApp)
&& intent != null && mSystemPreferredConfig.isEnabledAccessibilityService(intent.getComponent())
) {
if (DEBUG) Slog.d(TAG, "start enabled accessibility service" + intent.getComponent());
return true;
}
// 是否为安装完成的模拟辅助服务
// check start accessibility service
if ("android".equals(callerApp)
&& intent != null && mSystemPreferredConfig.isInstalledAccessibilityService(intent.getComponent())
&& isUserTouchActive()) {
if (DEBUG) Slog.d(TAG, "start installed accessibility service" + intent.getComponent());
return true;
}
// 是否为语音服务
// check start voice synthesize service
if (intent != null && mSystemPreferredConfig.isTTSAction(intent.getAction())
&& isUserTouchActive()) {
if (DEBUG) Slog.d(TAG, "start voice synthesize service" + intent.getAction());
return true;
}
// 是否为打印服务
// check start print service
if ("android".equals(callerApp)
&& intent != null && mSystemPreferredConfig.isInstalledPrintService(intent.getComponent())
&& isUserTouchActive()) {
if (DEBUG) Slog.d(TAG, "start installed print service" + intent.getComponent());
return true;
}
// for sina
if ( intent != null && "com.sina.weibo.remotessoservice".equals(intent.getAction())
&& "com.sina.weibo".equals(targetApp)) {
if (DEBUG) Slog.d(TAG, "allow Start:using sina to login:" +callerApp);
return true;
}
// 是否为通讯服务
// check start default phone service
if (intent != null && "android.telecom.InCallService".equals(intent.getAction())) {
if (DEBUG) Slog.d(TAG, "start default phone app:" + targetApp);
return true;
}
// 是否为没有启动入口的程序且为关联唤醒
if (mInstalledServiceList.contains(targetApp)
&& autoLaunchByOtherApp(targetApp, targetUid, callerApp, callerUid, reason)) {
if (DEBUG) Slog.d(TAG, "bind installed service :" + targetApp + " from " + callerApp);
return true;
}
// 是否为用户账户服务且用户当前正在触摸屏幕
if ("android".equals(callerApp)
&& intent != null && ACTION_AUTHENTICATOR_INTENT.equals(intent.getAction())
&& isUserTouchActive()) {
if (DEBUG) Slog.d(TAG, "bind Account service :" + targetApp + " from " + callerApp);
return true;
}
return false;
}
// 非常有创新的接口,用户当前是否有触摸屏幕操作
private boolean isUserTouchActive() {
long now = SystemClock.elapsedRealtime();
long lastTouchTime = 0;
if (mPowerControllerInternal != null)
lastTouchTime = mPowerControllerInternal.getLastTouchEventTimeStamp();
return ((now - lastTouchTime) <= 1000);
}
2.3 handleContentProviderStartAction
是否为 contentprovider 类型启动
private static final String REASON_CONTENT_PROVIDER = "contentprovider";
// return true: for should be allow to be started
// false: for others
private boolean handleContentProviderStartAction(Intent intent, String targetApp, int targetUid,
String callerApp, int callerUid, String reason) {
// 是否为 contentprovider 类型启动
if (!REASON_CONTENT_PROVIDER.equals(reason)) return false;
int targetAppType = mPowerControllerInternal.getAppCategoryType(targetApp);;
AppState callerAppState = mAppStateInfoCollector.getAppState(callerApp, UserHandle.getUserId(callerUid));
// 唤醒者是否为前台进程
boolean isCallerTopApp = false;
if (callerAppState != null
&&((callerAppState.mProcState == ActivityManager.PROCESS_STATE_TOP)
|| (callerAppState.mState == Event.MOVE_TO_FOREGROUND))
) {
isCallerTopApp = true;
}
// 唤醒者是否为前台进程且是否用户正在点击且是否为白名单或未知类型
if (isCallerTopApp && isUserTouchActive()
&& (inAssociateLaunchExceptionAppList(targetApp) || PowerDataBaseControl.UNKNOWN == targetAppType)) {
if (DEBUG) Slog.d(TAG,"allow Start: "+targetApp+", callingPackage = "+callerApp+ " reason = "+reason);
return true;
}
return false;
}
2.4 是否为输入法进程 isLaunchingIMEApp
private boolean isLaunchingIMEApp(Intent intent, String targetApp, int targetUid,
String callerApp, String reason) {
//handle inputmethod
// 是否为系统调用且为bind-service类型且为InputMethod的信号
if ("android".equals(callerApp)
&& REASON_BIND_SERVICE.equals(reason)
&& intent != null && "android.view.InputMethod".equals(intent.getAction())) {
if (targetApp != null) { // a input method
// 获取当前正在使用的输入法
int index = mEnabledInputMethodAppList.indexOf(targetApp);
// 若当前为正在使用输入法,则添加本输入法
if (index < 0) {
mEnabledInputMethodAppList.add(targetApp);
int userId = UserHandle.getUserId(targetUid);
mAppStateInfoCollector.updateAppInputMethodState(targetApp, true, userId);
mAppStateInfoCollector.setDefaultInputMethodApp(targetApp, userId);
}
}
return true;
}
// allow to start input Method
// 是否为系统调用且为bind-service类型且为当前使用输入法
if (REASON_BIND_SERVICE.equals(reason) && "android".equals(callerApp) && isInputMethodApp(targetApp)) {
if (DEBUG) Slog.d(TAG, "isLaunchingIMEApp: "+targetApp
+ ", callingPackage = "+callerApp+", reason = "+reason +" allow for input method");
return true;
}
return false;
}
// input method app
private boolean isInputMethodApp(String pkgName) {
int index = mEnabledInputMethodAppList.indexOf(pkgName);
if (index >= 0) {
return true;
}
return false;
}
2.5 是否允许 send-broadcast 类型启动-handleBroadcastAction
private static final String REASON_BROADCAST = "send-broadcast";
// 是否允许 send-broadcast 类型启动
if (handleBroadcastAction(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
return true;
}
private boolean handleBroadcastAction(Intent intent, String targetApp, int targetUid,
String callerApp, int callerUid, String reason) {
// 是否为send-broadcast类型校验
if (!REASON_BROADCAST.equals(reason) || intent == null) return false;
// 是否为系统调用且当前是桌面小部件广播
if (intent != null
&& "android".equals(callerApp)) {
String action = intent.getAction();
if (action != null && action.startsWith("android.appwidget.action.")) //AppWidget action
return true;
}
// 是否系统调用且为电话广播
// check out call for phone app
if ("android".equals(callerApp)
&& intent != null && Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())
&& mSystemPreferredConfig.isDefaultPhoneApp(targetApp)) {
if (DEBUG) Slog.d(TAG, "start phone app for out call:" + targetApp);
return true;
}
// 是否为短信广播
if (SMS_DELIVER_ACTION.equals(intent.getAction())) {
if (DEBUG) Slog.d(TAG, "start default sms app:" + targetApp);
return true;
}
// 是否为GMS推送服务广播
// receive GMS C2DM message for bug#787547
if ("com.google.android.gms".equals(callerApp)
&& "com.google.android.c2dm.intent.RECEIVE".equals(intent.getAction())) {
if (DEBUG) Slog.d(TAG, "start app:" + targetApp + " for receiving message");
return true;
}
return false;
}
2.6 是否允许语音识别 isRecognizerIntent
private boolean isRecognizerIntent(Intent intent, String targetApp, int targetUid,
String callerApp, int callerUid, String reason) {
AppState callerAppState = mAppStateInfoCollector.getAppState(callerApp, UserHandle.getUserId(callerUid));
if (isSystemApp(callerAppState)
&& REASON_START_ACTIVITY.equals(reason)
&& intent != null && RecognizerIntent.ACTION_WEB_SEARCH.equals(intent.getAction())) {
return true;
}
return false;
}
2.7 是否允许 CTS 或者adb shell 测试运行
vendor/sprd/platform/frameworks/base/services/core/java/com/android/server/power/Util.java
public static boolean isCts(String pkgName) {
if (pkgName == null) return false;
/*check if in internal white app list, like CTS app*/
for(String s : mCtsWhiteAppList) {
if(pkgName.contains(s)) {
return true;
}
}
// is cts app
if ((pkgName.startsWith("android.") && pkgName.contains(".cts."))
|| (pkgName.startsWith("android.") && pkgName.endsWith(".cts"))
|| (pkgName.startsWith("com.android.") && pkgName.contains(".cts."))
|| (pkgName.startsWith("com.android.") && pkgName.endsWith(".cts"))) {
return true;
}
// is gts app
if ((pkgName.startsWith("com.google.") && pkgName.contains(".gts."))
|| (pkgName.startsWith("com.google.") && pkgName.endsWith(".gts"))
|| (pkgName.startsWith("com.android.") && pkgName.contains(".gts."))
|| (pkgName.startsWith("com.android.") && pkgName.endsWith(".gts"))
|| (pkgName.startsWith("com.android.compatibility.") )
) {
return true;
}
return false;
}
private boolean isAutoTest(int callerUid, String callerApp, String targetApp) {
if (callerUid == Process.SHELL_UID) {
if (DEBUG) Slog.d(TAG, "calling from shell, see as doing auto test: " + targetApp);
return true;
}
return false;
}
2.8 判断进程是否已经启动
private boolean isAlreadyStarted(AppState appState) {
// if target app already exist
if ((appState != null
&& appState.mProcState < ActivityManager.PROCESS_STATE_CACHED_EMPTY // 不为 cache 或者 空进程
&& appState.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT) // 不为不存在状态
|| (appState != null
&& appState.mProcState == ActivityManager.PROCESS_STATE_CACHED_EMPTY // cache 或者 空进程
&& Event.NONE != appState.mState)) { // 不为空
return true;
}
return false;
}
2.9 标记当前启动状态
private static final int LAUNCH_STATE_AUTO = 0;
private static final int LAUNCH_STATE_ALLOW = 1;
private static final int LAUNCH_STATE_DENY = 2;
/**
* Check the preset, including:
* (1) system app should be allow to be self started
* (2) system app that is the launcher black app list should not be self started
*/
private int checkLaunchStateByPreset(Intent intent, String targetApp, int targetUid,
String callerApp, int callerUid, String reason) {
// 获取应用安装列表
ArrayMap<String, PackageInfo> mInstalledAppList = getInstalledAppList(UserHandle.getUserId(targetUid));
PackageInfo targetPkg = mInstalledAppList.get(targetApp);
// if not a system app, just return STATE_AUTO
// 若不为系统应用,则启动状态设为LAUNCH_STATE_AUTO
// targetPkg不为空 表示包含在第三方安装列表中
if (targetPkg != null) {
return LAUNCH_STATE_AUTO;
}
// 启动黑名单且不是用户主动点击
if (mPowerConfig != null && mPowerConfig.inLaunchBlackList(targetApp)
&& !launchedByUserActivity(intent, targetApp, targetUid, callerApp, callerUid, reason, true)) {
if (DEBUG) Slog.d(TAG, "in PowerConfig launch black list: " + targetApp + " denyed!!");
return LAUNCH_STATE_DENY;
}
return LAUNCH_STATE_ALLOW;
}
// 应用安装列表
private ArrayMap<String, PackageInfo> getInstalledAppList(int userId) {
ArrayMap<String, PackageInfo> mInstalledAppList = mInstalledAppListForUsers.get(userId);
if (mInstalledAppList == null) {
mInstalledAppList = new ArrayMap<>();
mInstalledAppListForUsers.put(userId, mInstalledAppList);
}
return mInstalledAppList;
}
// 启动黑名单
// /system/etc/pwctl_config.xml
public boolean inLaunchBlackList(String pkgName) {
int index = mConstants.mLaunchBlacklist.indexOf(pkgName);
if (index >= 0) {
return true;
}
return false;
}
- /system/etc/pwctl_config.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<config>
<item name="LaunchBlackList">
<packageName>com.pp.assistant</packageName>
</item>
</config>
2.9.1 是否为用户界面启动-launchedByUserActivity
private static final String REASON_START_ACTIVITY = "start-activity";
// check if this a launched operation by user
// INPUT: ignoreTouchTime if true, then don't see TouchElasedTime <= (1*1000) as a userActivity
// else see TouchElasedTime <= (1*1000) as a userActivity for Top App
// NOTE: this cannot decide exactly
// 本函数的逻辑确实容易疏漏,尤其是最后一个判断,觉得有点毁掉前面的苛刻的条件 - this cannot decide exactly
private boolean launchedByUserActivity(Intent intent, String targetApp, int targetUid,
String callerApp, int callerUid, String reason, boolean ignoreTouchTime) {
boolean userLaunched = false;
// 获取当前流逝时刻
long now = SystemClock.elapsedRealtime();
long lastTouchTime = 0;
AppState callerAppState = mAppStateInfoCollector.getAppState(callerApp, UserHandle.getUserId(callerUid));
if (mPowerControllerInternal != null) {
// 获取最近一次touch事件时间
lastTouchTime = mPowerControllerInternal.getLastTouchEventTimeStamp();
}
boolean isCallerTopApp = false;
// 重要进程定义:属性为前台进程或者为launch桌面进程或者正在切换为前台进程或当前发生了touch事件
if (callerAppState != null
&&((callerAppState.mProcState == ActivityManager.PROCESS_STATE_TOP)
|| (callerAppState.mProcState == ActivityManager.PROCESS_STATE_HOME)
|| (callerAppState.mState == Event.MOVE_TO_FOREGROUND)
|| (now - callerAppState.mLastTimeUsed) < 1000
|| isLauncherApp(callerApp)) // for Bug#712736
) {
isCallerTopApp = true;
}
// check the associated-starting because of third party push service
// 检查是否有进程push黑名单组件
// 1. 检查进程为重要进程
// 2. 且启动类型是为 start-activity
// 3. 且进程不是top进程
// 4. 且进程含有push黑名单组件
if (isCallerTopApp &&
REASON_START_ACTIVITY.equals(reason)
&& !isLauncherAction(intent)
&& intent != null
&& ThirdpartyPush.isAssociatedComponent(intent.getComponent())) {
if (DEBUG) Slog.d(TAG,"launchedByUserActivity : Start Proc : "+targetApp
+", callingPackage = "+callerApp
+ " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
+"), reason = "+reason
+ " Associated-Starting ThirdParty Push Service");
isCallerTopApp = false;
}
// see the caller of a launcher action as top app
// 是否为非重要进程且为top进程
// add for bug#776461
if (!isCallerTopApp && intent != null && isLauncherAction(intent)) {
isCallerTopApp = true;
}
if (DEBUG_MORE) {
Slog.d(TAG,"launchedByUserActivity : Start Proc : "+targetApp
+", callingPackage = "+callerApp
+ " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
+"), reason = "+reason);
}
long lastTouchElasedTime = now - lastTouchTime;
if (DEBUG) Slog.d(TAG, "lastTouchElasedTime: "+lastTouchElasedTime);
// 启动类型为 start-activityq且当前正在touch事件
if (isCallerTopApp
&& (REASON_START_ACTIVITY.equals(reason)
|| (!ignoreTouchTime && lastTouchElasedTime <= (1*1000)))
) {
// 判定用户主动点击事件
userLaunched = true;
}
// check if this call from "android"
// 检查调用者是否为android
// 1. isCallerTopApp false
// 2. 且启动类型是为 start-activity
// 3. 当前存在touch事件
// 4. android 进程当前属于前台属性
if (!isCallerTopApp && REASON_START_ACTIVITY.equals(reason) && lastTouchElasedTime <= (1*1000)) {
AppState androidState = mAppStateInfoCollector.getAppState("android", UserHandle.USER_SYSTEM);
if (androidState != null
&& (androidState.mState == Event.MOVE_TO_FOREGROUND
|| (now - androidState.mLastTimeUsed) < 1000)) {
// 判定用户主动点击事件
userLaunched = true;
}
}
// Bug#707888 setting monkey fail --> BEG
// 只要是系统应用就允许启动,这块我觉得做得不是很好
// for callerApp is system app, and use "start-activity", then allow
if ((callerAppState == null || callerAppState.mUid < Process.FIRST_APPLICATION_UID)
&& REASON_START_ACTIVITY.equals(reason)) {
userLaunched = true;
}
// Bug#707888 setting monkey fail <-- END
return userLaunched;
}
// 检测当前的action是不是启动界面程序,很好的方法
private boolean isLauncherAction(Intent intent) {
if (intent == null) return false;
if (Intent.ACTION_MAIN.equals(intent.getAction())
&& intent.hasCategory(Intent.CATEGORY_LAUNCHER)
&& (intent.getComponent() != null)) {
return true;
}
return false;
}
// a component name that will be used for associated-starting in third party push service
// such as getui push service
private final static String[] mAssociatedComponentNameList = new String[] {
"com.igexin.sdk.GActivity", // 这个组件很贱,经常伪装前台进程唤醒
};
2.10 检查省电管理设置界面的黑白名单
检查预设值白名单和省电管理界面白名单进行判断是否需要允许启动,再次进行launchState设置
// return launch state according to user setting
private int checkLaunchStateByUserSetting(Intent intent, String targetApp, int targetUid,
String callerApp, int callerUid, String reason) {
// targetApp 进程不存在 或 targetApp 为 callerApp,表明为自启动
if (targetApp == null || targetApp.equals(callerApp))
return LAUNCH_STATE_AUTO;
// 检查是否为第三方应用启动
boolean launchByOther = autoLaunchByOtherApp(targetApp, targetUid, callerApp, callerUid, reason);
// allow app in whitelist
// 检查是否为CTS应用或者pwctl_config.xml配置的白名单
if (inSelfStartWhiteAppList(targetApp)) {
return LAUNCH_STATE_ALLOW;
}
// if in ultrasaving mode, don't allow autostart except apps in ultrasve applist
// 1. 且 非关联启动
// 2. 且 当前为超级省电模式
// 3. 且 下一个模式为超级省电模式
if (!launchByOther && (PowerManagerEx.MODE_ULTRASAVING == mPowerSaveMode)
&& (PowerManagerEx.MODE_ULTRASAVING == mNextPowerSaveMode)) {
// 获取超级省电白名单
List<String> appList = mPowerControllerInternal.getAppList_UltraMode();
if (!appList.contains(targetApp)) {
if (DEBUG) Slog.d(TAG, "app: " + targetApp + " in applist of ultramode, refuse to autostart, denyed");
// 非超级省电白名单禁止启动
return LAUNCH_STATE_DENY;
}
}
// 获取省电设置界面的自启动设置情况
int autoLaunch = mPowerControllerInternal.getAppPowerSaveConfgWithTypeInternal(targetApp,AppPowerSaveConfig.ConfigType.TYPE_AUTOLAUNCH.value);
// 获取省电设置界面的关联启动设置情况
int secondLaunch = mPowerControllerInternal.getAppPowerSaveConfgWithTypeInternal(targetApp,AppPowerSaveConfig.ConfigType.TYPE_SECONDARYLAUNCH.value);
// public static final int VALUE_INVALID = -1;
// public static final int VALUE_AUTO = 0; 自动
// public static final int VALUE_OPTIMIZE = 1; 省电优化或禁止 即黑名单
// public static final int VALUE_NO_OPTIMIZE = 2; 省电不优化或允许 即白名单
// 1. 或 自启动白名单且没有被第三方应用关联启动
// 2. 或 关联唤醒白名单且被第三方应用关联启动
if (((autoLaunch == AppPowerSaveConfig.VALUE_NO_OPTIMIZE) && !launchByOther)
|| ((secondLaunch == AppPowerSaveConfig.VALUE_NO_OPTIMIZE) && launchByOther)) {
if (DEBUG) Slog.d(TAG, "bgclean judgeAppLaunchAllowed: "+targetApp
+ ", callingPackage = "+callerApp+", reason = "+reason +" in my whitelist");
// 允许启动
return LAUNCH_STATE_ALLOW;
}
// 检查应用是否为黑名单
//check whether app is in black list
boolean bInBlackList = false;
// 1. 且 自启动黑名单
// 2. 且 非被其他应用关联唤醒
if ((autoLaunch == AppPowerSaveConfig.VALUE_OPTIMIZE) && !launchByOther) {
if (DEBUG_MORE) Slog.d(TAG, "in apppowerconfig autolaunch black list: " + targetApp);
// 标记为黑名单flag
bInBlackList = true;
}
// 1. 且 关联唤醒黑名单
// 2. 且 被启动应用关联唤醒
if ((secondLaunch == AppPowerSaveConfig.VALUE_OPTIMIZE) && launchByOther) {
if (DEBUG_MORE) Slog.d(TAG, "in apppowerconfig 2ndlaunch black list: " + targetApp);
// 标记为黑名单flag
bInBlackList = true;
}
// check whether blacklist app is in exception
if (bInBlackList) {
// not allow auto start app that in auto start black list
// 1. in mAutoLaunch_BlackList AND is not launched by other app (that is launched by system broadcast etc)
// 2. NOTE: Exception:
// 1) Start reason is REASON_START_ACTIVITY (this is alway happened in case of
// app use another app to do something, including launcher to launch a app)
// 2) Self start self ( that is this app is alreadby started, and is start some activity internal)
// 1. 且 非关联启动
// 2. 且 非start-activity 类型启动
if (!launchByOther && !REASON_START_ACTIVITY.equals(reason)) {
if (DEBUG) Slog.d(TAG, "in autolaunch black list: "+targetApp
+ ", callingPackage = "+callerApp+", reason = "+reason +" denyed!");
// 设置为禁止启动状态
return LAUNCH_STATE_DENY;
}
// not allow auto start by other app that in secondary start black list
// 1. in m2ndLaunch_BlackList AND is launched by other app
// 2. NOTE: Exception:
// 1) when callerApp is top AND Start reason is REASON_START_ACTIVITY (this is alway happened in case of
// app use another app to do something, including launcher to launch a app)
// 2) Self start self ( that is this app is alreadby started, and is start some activity internal)
// 3) when callerApp is top AND targetApp is in AssociateLaunchExceptionAppList
// 1. 且 关联启动
// 2. 且非用户主动点击
if (launchByOther && !launchedByUserActivity(intent, targetApp, targetUid, callerApp, callerUid, reason, true)) {
if (DEBUG) Slog.d(TAG, "in 2ndlaunch black list: "+targetApp
+ ", callingPackage = "+callerApp+", reason = "+ reason + " intent:" + intent + " denyed!");
return LAUNCH_STATE_DENY;
}
// Although it is black list, but it start by user, so allowed to start
return LAUNCH_STATE_ALLOW;
}
return LAUNCH_STATE_AUTO;
}
2.10.1 是否为白名单应用启动
private boolean inSelfStartWhiteAppList(String pkgName) {
if (inCommonWhiteAppList(pkgName))
return true;
// if setting in the LaunchWhiteList in pwctl_config.xml
if (mPowerConfig != null && mPowerConfig.inLaunchWhiteList(pkgName)) {
if (DEBUG) Slog.d(TAG, "in PowerConfig launch white list: " + pkgName);
return true;
}
return false;
}
/**
* 这里主要为CTS
* Common white list, that is for both lockScreen manager and auto self starting manager
*/
private boolean inCommonWhiteAppList(String pkgName) {
if (pkgName == null) return true;
/** auto start and lock screen clean do not need to care about doze white list
* try {
* if (mPowerControllerInternal.isWhitelistApp(pkgName)) {
* return true;
* }
* } catch (Exception e) {
* }
*/
// 在 /system/etc/pwctl_config.xml 目录预先配置的白名单
/*check if in internal white app list, like CTS app*/
for(String s : mInternalWhiteAppList) {
if(pkgName.contains(s)) {
if (DEBUG) Slog.d(TAG, "Internal white applist: " + pkgName);
return true;
}
}
// is cts/gts app
if (Util.isCts(pkgName)) {
if (DEBUG) Slog.d(TAG, "CTS/GTS app: " + pkgName + ", see as in white list!!");
return true;
}
return false;
}
// This white list is used for some app like CTS
private final String[] mInternalWhiteAppList = new String[] {
"com.google.android.gms",
"com.google.android.gsf",
"android.app.cts",
"com.android.cts",
"android.icu.dev.test.util"
};
public boolean inLaunchWhiteList(String pkgName) {
int index = mConstants.mLaunchWhitelist.indexOf(pkgName);
if (index >= 0) {
return true;
}
return false;
}
2.11 待机模式下禁止动态待机黑名单启动
// 待机模式下禁止第三方应用启动
// not allow third party app that has been force stopped during standby
// to be started again
// 1. 待机时长大于0
// 2. 是否为待机模式禁止被启动的应用
if (mStandbyStartTime > 0 && isForceStoppedAppDuringStandby(targetApp, targetUid)) {
if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed (has been force stopped)!!");
return false;
}
===============================================================================================================
// to recode the system elapsed time when starting standby
private long mStandbyStartTime = 0;
/*
* Note device is enter standby state ( screen off / unpluged)
*/
void noteDeviceStateChanged(boolean bStandby, final long nowELAPSED) {
if (DEBUG) Slog.d(TAG, "noteDeviceStateChanged bStandby:" + bStandby);
// 更新待机时间
if (bStandby) mStandbyStartTime = nowELAPSED; //SystemClock.elapsedRealtime();
else mStandbyStartTime = 0;
....
}
===============================================================================================================
// 是否为待机模式禁止被启动的应用
private boolean isForceStoppedAppDuringStandby(String pkgName, int uid) {
ArrayMap<String, Integer> mStoppedAppList = getStoppedAppList(UserHandle.getUserId(uid));
return mStoppedAppList.containsKey(pkgName);
}
private ArrayMap<String, Integer> getStoppedAppList(int userId) {
ArrayMap<String, Integer> mStoppedAppList = mStoppedAppListForUsers.get(userId);
// 对应的userid不存在,则加入StoppedAppList中,便于下次待机中可以取到名单吗?这个逻辑暂时有些绕,存在疑问
if (mStoppedAppList == null) {
mStoppedAppList = new ArrayMap<>();
mStoppedAppListForUsers.put(userId, mStoppedAppList);
}
return mStoppedAppList;
}
// Apps that have be stopped during this standby period
// it will clear when exit standby state
//private ArrayList<String> mStoppedAppList = new ArrayList<>();
private SparseArray<ArrayMap<String,Integer>> mStoppedAppListForUsers = new SparseArray<>(); //<pkgName, userId>
2.12 禁止系统广播启动第三方应用
这里与 handleBroadcastAction()函数功能存在重复,且 handleBroadcastAction 的规避条件更多一些,或者本意是禁止 handleBroadcastAction 没有涉及的一些广播
=================================================================================================
// not allow system broadcast to launch third party app
// 1. caller 不为空
// 2. caller 为系统(android)
// 3. 启动类型是 send-broadcast
if ((callerAppState == null ||(callerApp != null && callerApp.equals("android")))
&& REASON_BROADCAST.equals(reason)) {
if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!!");
return false;
}
2.13 禁止system ui广播启动第三方应用
// 禁止"system ui"广播启动第三方应用
// not allow "com.android.systemui" broadcast to launch third party app
// 1. caller 为system ui
// 2. 启动类型为send-broadcast
if (callerApp != null && callerApp.equals("com.android.systemui")
&& REASON_BROADCAST.equals(reason)) {
if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!!");
return false;
}
2.14 不允许后台应用关联唤醒其他应用
- frameworks/base/core/java/android/app/ActivityManager.java
// not allow background app to launch other third party app
// 不允许后台应用关联唤醒其他应用
// 1. caller 不用空
// 2. caller 状态为非前台进程,mProcState 数值越大进程重要度越低
// 3. 启动类型不为 start-acitivty
if (callerAppState != null && callerAppState.mProcState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
&& !REASON_START_ACTIVITY.equals(reason)) {
if (DEBUG) {
Slog.d(TAG,"Start Proc : "+targetApp
+", callingPackage = "+callerApp
+ " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
+"), reason = "+reason
+ ": denyed!!");
}
return false;
}
/** @hide Process is a persistent system process. */
public static final int PROCESS_STATE_PERSISTENT = 0;
/** @hide Process is a persistent system process and is doing UI. */
public static final int PROCESS_STATE_PERSISTENT_UI = 1;
/** @hide Process is hosting the current top activities. Note that this covers
* all activities that are visible to the user. */
public static final int PROCESS_STATE_TOP = 2;
/** @hide Process is hosting a foreground service due to a system binding. */
public static final int PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 3;
/** @hide Process is hosting a foreground service. */
public static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;
/** @hide Same as {@link #PROCESS_STATE_TOP} but while device is sleeping. */
public static final int PROCESS_STATE_TOP_SLEEPING = 5;
/** @hide Process is important to the user, and something they are aware of. */
public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 6;
/** @hide Process is important to the user, but not something they are aware of. */
public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 7;
/** @hide Process is in the background transient so we will try to keep running. */
public static final int PROCESS_STATE_TRANSIENT_BACKGROUND = 8;
/** @hide Process is in the background running a backup/restore operation. */
public static final int PROCESS_STATE_BACKUP = 9;
/** @hide Process is in the background, but it can't restore its state so we want
* to try to avoid killing it. */
public static final int PROCESS_STATE_HEAVY_WEIGHT = 10;
/** @hide Process is in the background running a service. Unlike oom_adj, this level
* is used for both the normal running in background state and the executing
* operations state. */
public static final int PROCESS_STATE_SERVICE = 11;
/** @hide Process is in the background running a receiver. Note that from the
* perspective of oom_adj receivers run at a higher foreground level, but for our
* prioritization here that is not necessary and putting them below services means
* many fewer changes in some process states as they receive broadcasts. */
public static final int PROCESS_STATE_RECEIVER = 12;
/** @hide Process is in the background but hosts the home activity. */
public static final int PROCESS_STATE_HOME = 13;
/** @hide Process is in the background but hosts the last shown activity. */
public static final int PROCESS_STATE_LAST_ACTIVITY = 14;
/** @hide Process is being cached for later use and contains activities. */
public static final int PROCESS_STATE_CACHED_ACTIVITY = 15;
/** @hide Process is being cached for later use and is a client of another cached
* process that contains activities. */
public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 16;
/** @hide Process is being cached for later use and is empty. */
public static final int PROCESS_STATE_CACHED_EMPTY = 17;
/** @hide Process does not exist. */
public static final int PROCESS_STATE_NONEXISTENT = 18;
/** @hide The lowest process state number */
public static final int MIN_PROCESS_STATE = PROCESS_STATE_PERSISTENT;
/** @hide The highest process state number */
public static final int MAX_PROCESS_STATE = PROCESS_STATE_NONEXISTENT;
2.15 不允许长时间运行的后台应用唤醒其他应用
======================================================================================
// not allow long idle third party app to start other third party app
// 1. caller 状态不为空
// 2. caller 非第三应用
// 3. caller 不为前台进程属性
// 4. 启动类型非start-activity
if (callerAppState != null && !isSystemApp(callerAppState)
&& callerAppState.mState != Event.MOVE_TO_FOREGROUND
&& callerAppState.mProcState != ActivityManager.PROCESS_STATE_TOP
&& !REASON_START_ACTIVITY.equals(reason)) {
// 当前流逝时刻
long nowELAPSED = SystemClock.elapsedRealtime();
// 待机场景持续时长
long idleDuration = 0;
// 待机场景持续时长 = 当前流逝时刻 - caller 最近一次运行时长
idleDuration = (callerAppState.mLastTimeUsed > 0 ? (nowELAPSED -callerAppState.mLastTimeUsed) : -1);
// 第三方应用在后台运行超过 DENY_START_APP_THRESHOLD,则不允许第三方进程
// 即不允许长时间运行的后台应用唤醒其他应用
if (idleDuration > DENY_START_APP_THRESHOLD) {
if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!! long idle");
return false;
}
}
======================================================================================
// if a non-top app has been idle for DENY_START_APP_THRESHOLD
// then don't allow this app to start other 3-party app
// 5 分钟 或者 30 分钟
private final long DENY_START_APP_THRESHOLD = (TEST ? 5 * 60 * 1000L : 30 * 60 * 1000L);