最近遇到一个STK测试case的问题,在Android Q平台上一直是验证pass的,但是在Android R上测试fail:
测试case要求不显示dialog,但是实际行为是显示dialog的,从逻辑上看有两处代码调用launchTextDialog()方法,为了精确定位在这里加了log,发现是因为isScreenIdle()方法为true导致进入内部else逻辑
闲话少说,上代码:
if (!(msg.isHighPriority || mStkContext[slotId].mMenuIsVisible
|| mStkContext[slotId].mDisplayTextDlgIsVisibile || isTopOfStack())) {
if(!isScreenIdle()) {
CatLog.d(LOG_TAG, "Screen is not idle");
sendScreenBusyResponse(slotId);
} else {
launchTextDialog(slotId);
}
} else {
launchTextDialog(slotId);
}
launchTextDialog()方法主要操作是为了弹出一个dialog,这里不再详细说明
上代码:
/* package */ boolean isScreenIdle() {
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (tasks == null || tasks.isEmpty()) {
return false;
}
String top = tasks.get(0).topActivity.getPackageName();
if (top == null) {
return false;
}
// We can assume that the screen is idle if the home application is in the foreground.
final Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_HOME);
ResolveInfo info = getPackageManager().resolveActivity(intent,
PackageManager.MATCH_DEFAULT_ONLY);
if (info != null) {
if (top.equals(info.activityInfo.packageName)) {
return true;
}
}
return false;
}
显而易见,只有
if (top.equals(info.activityInfo.packageName)) {
return true;
}
此时,才会返回true,那么很简单,打个log看下top和info.activityInfo.packageName()分别是什么不就可以了:
log如下:
01-01 15:06:41.696 2853 14373 D CAT : StkAppService: this top is: com.tcl.android.launcher
01-01 15:06:41.701 2853 14373 D CAT : StkAppService: this info is: com.tcl.android.launcher, intent is: Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] }
top和info都是launch,此时有些懵逼,我此时界面切到的是camera,topActivity应该是camera,不应该是launch啊,为了证实这点我又抓了下dump
adb shell dumpsys activity > dump.txt
抓出来topActivity确实是camera,那就奇怪了,所以这时候看了下代码获取topActivity的方法:
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (tasks == null || tasks.isEmpty()) {
return false;
}
String top = tasks.get(0).topActivity.getPackageName();
ActivityManager.getRunningTask()这个方法从Android L上就已经废弃了,Google是这样描述的
* @deprecated As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method
* is no longer available to third party
* applications: the introduction of document-centric recents means
* it can leak person information to the caller. For backwards compatibility,
* it will still return a small subset of its data: at least the caller's
* own tasks, and possibly some other tasks
* such as home that are known to not be sensitive
从注释上可以看到,三方apk不允许使用这个方法了,但是问题在于从Android L上就不允许三方应用使用了,但是Android Q上为什么会是pass的呢?这时候就想到了权限问题。
查代码看了下权限这边的问题,发现这样的调用顺序:
ActivityManager.getRunningTasks() > ActivityTaskManagerService.getTasks() > ActivityTaskManagerService().getFilteredTasks() > isGetTasksAllowed()
在 isGetTasksAllowed()方法中有一个权限检查的代码:
boolean allowed = checkGetTasksPermission(android.Manifest.permission.REAL_GET_TASKS,
callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
if (!allowed) {
if (checkGetTasksPermission(android.Manifest.permission.GET_TASKS,
callingPid, callingUid) == PackageManager.PERMISSION_GRANTED) {
// Temporary compatibility: some existing apps on the system image may
// still be requesting the old permission and not switched to the new
// one; if so, we'll still allow them full access. This means we need
// to see if they are holding the old permission and are a system app.
try {
if (AppGlobals.getPackageManager().isUidPrivileged(callingUid)) {
allowed = true;
if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
+ " is using old GET_TASKS but privileged; allowing");
}
} catch (RemoteException e) {
}
}
if (DEBUG_TASKS) Slog.w(TAG, caller + ": caller " + callingUid
+ " does not hold REAL_GET_TASKS; limiting output");
}
return allowed;
首先会检查有没有 REAL_GET_TASKS 权限,如果有,直接返回true,如果没有则会检查 GET_TASKS 权限,查了下STK的权限设置,确实是没有这个权限的,那为什么Android Q上是pass的呢?
查了下Android R上关于STK的提交,原来Google的一个NC程序员给去掉了,本来想重新提交到Google的,发现这个NC又给加回来了…
很简单,加上 REAL_GET_TASKS 权限就ok了,但是只有系统应用才可以,三方应用建议还是加上 GET_TASKS 权限。
<uses-permission android:name="android.permission.REAL_GET_TASKS" />