还是先看官方文档: developer.android.google.cn/about/versi…
在官方文档的重大变更里面,介绍了一条隐私性调整声明:
Restrictions on starting activities from the background
Starting in Android 10, the system places restrictions on starting activities from the background. This behavior change helps minimize interruptions for the user and keeps the user more in control of what's shown on their screen. As long as your app starts activities as a direct result of user interaction, your app most likely isn't affected by these restrictions.
To learn more about the recommended alternative to starting activities from the background, see the guide on how to alert users of time-sensitive events in your app.
大概意思就是说增加了对后台应用启动Activity的限制,让使用者能更好的决定自己的屏幕应该显示什么内容。这样主要考虑的还是安全性,当然一定程度上也会优化系统的performance。比如:
- 用户在看视频或玩游戏时不会被其他弹窗打断
- 避免流氓软件的弹窗
那么对于开发者来说,如何判断你的Activity被AMS挡掉了?可以搜索下这段log
Background activity start
这段log是默认打印的,Activity的启动过程就不再介绍了,有很多Activity生命周期的文档可以参考。
/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
939 boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
940 final String callingPackage, int realCallingUid, int realCallingPid,
941 WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
942 boolean allowBackgroundActivityStart, Intent intent) {
943 // don't abort for the most important UIDs
944 final int callingAppId = UserHandle.getAppId(callingUid);
945 if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
946 || callingAppId == Process.NFC_UID) {
947 return false;
948 }
949 // don't abort if the callingUid has a visible window or is a persistent system process
950 final int callingUidProcState = mService.getUidState(callingUid);
951 final boolean callingUidHasAnyVisibleWindow =
952 mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid);
953 final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow
954 || callingUidProcState == ActivityManager.PROCESS_STATE_TOP
955 || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
956 final boolean isCallingUidPersistentSystemProcess =
957 callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
958 if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) {
959 return false;
960 }
1044 // anything that has fallen through would currently be aborted
1045 Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
1046 + "; callingUid: " + callingUid
1047 + "; isCallingUidForeground: " + isCallingUidForeground
1048 + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess
1049 + "; realCallingUid: " + realCallingUid
1050 + "; isRealCallingUidForeground: " + isRealCallingUidForeground
1051 + "; isRealCallingUidPersistentSystemProcess: "
1052 + isRealCallingUidPersistentSystemProcess
1053 + "; originatingPendingIntent: " + originatingPendingIntent
1054 + "; isBgStartWhitelisted: " + allowBackgroundActivityStart
1055 + "; intent: " + intent
1056 + "; callerApp: " + callerApp
1057 + "]");
这段代码很长,我们只需要知道,当你的Activity从后台启动被挡掉之后,是一定会打印这段log出来的。想要研究shouldAbortBackgroundActivityStart的流程可以再去添加callback,这个都很简单。我们要关注的是这段log中传达的信息
- callingPackage:调用此Activity的包名
- isCallingUidForeground:是否为前台用户组调用的
- isBgStartWhitelisted:是否在允许从后台启动的白名单中
其中最关键的就是第三个位置,isBgStartWhitelisted,我们可以直接从log中看到这里是true or false,很显然这里打印的是allowBackgroundActivityStart的布尔值,很显然如果这里打印false,说明这个activity是不允许从后台启动的。这个是使用startActivity的过程。那如果调用startActivities来批量启动Activity呢?
/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
1014 @Override
1015 public final int startActivities(IApplicationThread caller, String callingPackage,
1016 Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions,
1017 int userId) {
1018 final String reason = "startActivities";
1019 enforceNotIsolatedCaller(reason);
1020 userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason);
1021 // TODO: Switch to user app stacks here.
1022 return getActivityStartController().startActivities(caller, -1, 0, -1, callingPackage,
1023 intents, resolvedTypes, resultTo, SafeActivityOptions.fromBundle(bOptions), userId,
1024 reason, null /* originatingPendingIntent */,
1025 false /* allowBackgroundActivityStart */);
1026 }
不用管多余的流程,直接看关键点,在ActivityTaskManagerService中,实际启动Activity时,是通过ActivityStartController来一次性启动多个activity的,这里直接僵硬的把代表allowBackgroundActivityStart的位置写入了false,在批量启动activity时,不允许从后台启动activity。
对于其他一些特殊Activity的启动,有时候会根据启动方式设置allowBackgroundActivityStart为true,也就是直接在构建ActivityStarter的时候调用 setAllowBackgroundActivityStart(true)直接写入一个true。
2908 ActivityStarter setAllowBackgroundActivityStart(boolean allowBackgroundActivityStart) {
2909 mRequest.allowBackgroundActivityStart = allowBackgroundActivityStart;
2910 return this;
2911 }
2910
当然这个对应用层是不开放的,只是在ATMS中启动某些特殊的activity时会添加这个值。
最终是否允许从后台启动Activity都会被传入到
/frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.java
266 final int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
267 String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
268 String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
269 int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
270 PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
271
272 userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid,
273 reason);
274
275 // TODO: Switch to user app stacks here.
276 return obtainStarter(intent, reason)
277 .setCallingUid(uid)
278 .setRealCallingPid(realCallingPid)
279 .setRealCallingUid(realCallingUid)
280 .setCallingPackage(callingPackage)
281 .setResolvedType(resolvedType)
282 .setResultTo(resultTo)
283 .setResultWho(resultWho)
284 .setRequestCode(requestCode)
285 .setStartFlags(startFlags)
286 .setActivityOptions(options)
287 .setMayWait(userId)
288 .setInTask(inTask)
289 .setOriginatingPendingIntent(originatingPendingIntent)
290 .setAllowBackgroundActivityStart(allowBackgroundActivityStart)
291 .execute();
292 }
在Anroid 10中到这里就结束了,Android 11中对什么样的Activity允许从后台启动,做了更详细的解释,参考这个函数shouldAbortBackgroundActivityStart
/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
1234 boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
1235 final String callingPackage, int realCallingUid, int realCallingPid,
1236 WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
1237 boolean allowBackgroundActivityStart, Intent intent) {
1238 // don't abort for the most important UIDs
1239 final int callingAppId = UserHandle.getAppId(callingUid);
1240 if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
1241 || callingAppId == Process.NFC_UID) {
1242 if (DEBUG_ACTIVITY_STARTS) {
1243 Slog.d(TAG, "Activity start allowed for important callingUid (" + callingUid + ")");
1244 }
1245 return false;
1246 }
1247
1248 // don't abort if the callingUid has a visible window or is a persistent system process
1249 final int callingUidProcState = mService.getUidState(callingUid);
1250 final boolean callingUidHasAnyVisibleWindow =
1251 mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid);
1252 final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow
1253 || callingUidProcState == ActivityManager.PROCESS_STATE_TOP
1254 || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
1255 final boolean isCallingUidPersistentSystemProcess =
1256 callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
1257 if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) {
1258 if (DEBUG_ACTIVITY_STARTS) {
1259 Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid
1260 + ", isCallingUidPersistentSystemProcess = "
1261 + isCallingUidPersistentSystemProcess);
1262 }
1263 return false;
1264 }
1265 // take realCallingUid into consideration
1266 final int realCallingUidProcState = (callingUid == realCallingUid)
1267 ? callingUidProcState
1268 : mService.getUidState(realCallingUid);
1269 final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
1270 ? callingUidHasAnyVisibleWindow
1271 : mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(realCallingUid);
1272 final boolean isRealCallingUidForeground = (callingUid == realCallingUid)
1273 ? isCallingUidForeground
1274 : realCallingUidHasAnyVisibleWindow
1275 || realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP;
1276 final int realCallingAppId = UserHandle.getAppId(realCallingUid);
1277 final boolean isRealCallingUidPersistentSystemProcess = (callingUid == realCallingUid)
代码太长就不贴上来了,这个api可以去研究一下返回值,如果这里返回true表示拦截此启动过程,返回false表示不拦截,根据判断条件简单筛查了一下,几个比较常见的允许从后台启动Activity的情况
- 如果是系统里比较重要的用户组发出来的请求,允许从后台启动Activity
1238 // don't abort for the most important UIDs
1239 final int callingAppId = UserHandle.getAppId(callingUid);
1240 if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
1241 || callingAppId == Process.NFC_UID) {
1242 if (DEBUG_ACTIVITY_STARTS) {
1243 Slog.d(TAG, "Activity start allowed for important callingUid (" + callingUid + ")");
1244 }
1245 return false;
1246 }
- 当前环形Activity的进程在前台拥有非dialog类型的可见窗口,或属于系统进程
1257 if (callingUidHasAnyVisibleWindow || isCallingUidPersistentSystemProcess) {
1258 if (DEBUG_ACTIVITY_STARTS) {
1259 Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid
1260 + ", isCallingUidPersistentSystemProcess = "
1261 + isCallingUidPersistentSystemProcess);
1262 }
1263 return false;
1264 }
- 在白名单内
1291 // wasn't whitelisted to start an activity
1292 if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
1293 if (DEBUG_ACTIVITY_STARTS) {
1294 Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
1295 + ") is persistent system process AND intent sender whitelisted "
1296 + "(allowBackgroundActivityStart = true)");
1297 }
1298 return false;
1299 }
- 拥有 START_ACTIVITIES_FROM_BACKGROUND 权限
1310 // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
1311 if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
1312 == PERMISSION_GRANTED) {
1313 if (DEBUG_ACTIVITY_STARTS) {
1314 Slog.d(TAG,
1315 "Background activity start allowed: START_ACTIVITIES_FROM_BACKGROUND "
1316 + "permission granted for uid "
1317 + callingUid);
1318 }
1319 return false;
1320 }
还有其他一些返回条件,不过相对少见一点。清楚后台启动Activity为何会被挡掉之后,解决此问题就容易了,如果我们只是为了debug某些问题,可以这样修改
/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
5404 boolean isBackgroundActivityStartsEnabled() {
5405 //return mAmInternal.isBackgroundActivityStartsEnabled();
return true;
5406 }
这里直接return true,试下Activity现在是否可以正常启动了,如果确定Activity无法启动时因为被background start限制了,可以为APP添加 START_ACTIVITIES_FROM_BACKGROUND权限,这部分就与AMS无关了,具体可以参考Android permission相关资料。如果是厂商自己的apk,还可以直接把自己加到白名单。