今天测试同事提了个问题单,进入设置里边的应用的权限管理,把所有权限关闭掉,然后打开这个应用,会弹出请求权限的对话框,然后按任务键,再打开权限窗口,将一个权限打开,再关闭,再按任务键,再打开应用,如此反复,四次之后,再打开应用时,同意所有权限,完成后应用窗口退出了,退回到桌面了。拿到题目了,自己先根据测试同事的描述,自己试了下,确实是这样,而且操作四次,必现;好,像这种必现问题单就好搞了,最害怕那种偶现的了。
自己模拟现象抓日志,从日志中得到了比较明显的答案,原来是由于某种原因,当前进程的窗口被销毁了,所以在用户操作时,还没有到最后一步同意权限时,进程的窗口已经被销毁了。好,那现在要作的就是找出原因,给测试同事一个完美的解释,为什么进程的窗口被销毁了?
Line 4841: 09-22 10:40:51.854 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.READ_CONTACTS
Line 5596: 09-22 10:40:55.601 I/ActivityManager( 1377): Killing 6593:com.android.capsensorforsar/u0a45, isShadow:false (adj 15): empty #17
Line 5739: 09-22 10:40:57.221 I/AppPermissionGroup( 7163): mAppSupportsRuntimePermissions = true
Line 5740: 09-22 10:40:57.221 I/AppPermissionGroup( 7163): grant permission, name = android.permission.READ_PHONE_STATE
Line 5742: 09-22 10:40:57.223 I/AppPermissionGroup( 7163): grant permission, name = android.permission.CALL_PHONE
Line 5827: 09-22 10:40:57.504 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.READ_PHONE_STATE
Line 5831: 09-22 10:40:57.528 W/ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100
Line 5832: 09-22 10:40:57.528 W/ActivityManager( 1377): killPackageProcessesLocked setAdj:-12, app.setAdj:-100
Line 5833: 09-22 10:40:57.529 W/ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100
Line 5834: 09-22 10:40:57.529 W/ActivityManager( 1377): killPackageProcessesLocked setAdj:-12, app.setAdj:-100
Line 5836: 09-22 10:40:57.529 I/ActivityManager( 1377): Killing 7348:com.letv.android.note/u0a27, isShadow:false (adj 9): permissions revoked
Line 5845: 09-22 10:40:57.656 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.CALL_PHONE
Line 6733: 09-22 10:41:03.386 I/AppPermissionGroup( 7163): mAppSupportsRuntimePermissions = true
Line 6734: 09-22 10:41:03.386 I/AppPermissionGroup( 7163): grant permission, name = android.permission.READ_CALENDAR
Line 6739: 09-22 10:41:03.389 I/AppPermissionGroup( 7163): grant permission, name = android.permission.WRITE_CALENDAR
Line 6821: 09-22 10:41:03.617 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.READ_CALENDAR
Line 6825: 09-22 10:41:03.638 W/ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100
Line 6826: 09-22 10:41:03.638 W/ActivityManager( 1377): killPackageProcessesLocked setAdj:-12, app.setAdj:-100
Line 6827: 09-22 10:41:03.638 W/ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100
Line 6828: 09-22 10:41:03.638 W/ActivityManager( 1377): killPackageProcessesLocked setAdj:-12, app.setAdj:-100
Line 6830: 09-22 10:41:03.639 I/ActivityManager( 1377): Killing 7398:com.letv.android.note/u0a27, isShadow:false (adj 9): permissions revoked
Line 6848: 09-22 10:41:03.721 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.WRITE_CALENDAR
Line 7865: 09-22 10:41:09.441 I/AppPermissionGroup( 7163): mAppSupportsRuntimePermissions = true
Line 7866: 09-22 10:41:09.441 I/AppPermissionGroup( 7163): grant permission, name = android.permission.READ_EXTERNAL_STORAGE
Line 7896: 09-22 10:41:09.542 I/AppPermissionGroup( 7163): grant permission, name = android.permission.WRITE_EXTERNAL_STORAGE
Line 7957: 09-22 10:41:10.853 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.READ_EXTERNAL_STORAGE
Line 7961: 09-22 10:41:10.883 W/ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100
Line 7962: 09-22 10:41:10.883 W/ActivityManager( 1377): killPackageProcessesLocked setAdj:-12, app.setAdj:-100
Line 7964: 09-22 10:41:10.883 W/ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100
Line 7965: 09-22 10:41:10.883 W/ActivityManager( 1377): killPackageProcessesLocked setAdj:-12, app.setAdj:-100
Line 7966: 09-22 10:41:10.884 I/ActivityManager( 1377): Killing 7445:com.letv.android.note/u0a27, isShadow:false (adj 9): permissions revoked
Line 7974: 09-22 10:41:11.090 W/ActivityManager( 1377): Force removing ActivityRecord{5e97987 u0 com.letv.android.note/.NoteListActivity, isShadow:false t4}: app died, no saved state
Line 7976: 09-22 10:41:11.095 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.WRITE_EXTERNAL_STORAGE
Line 8581: 09-22 10:41:15.018 I/AppPermissionGroup( 7163): mAppSupportsRuntimePermissions = true
Line 8582: 09-22 10:41:15.018 I/AppPermissionGroup( 7163): grant permission, name = android.permission.GET_ACCOUNTS
Line 8587: 09-22 10:41:15.020 I/AppPermissionGroup( 7163): grant permission, name = android.permission.READ_CONTACTS
然后展开搜索,ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100这句日志应该是ActivityManagerService中打印的,在ActivityManagerService中搜索一下,确实是这样。这句日志是从ActivityManagerService类的killPackageProcessesLocked方法打印的,具体方法代码如下:
private final boolean killPackageProcessesLocked(String packageName, int appId,
int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
boolean doit, boolean evenPersistent, String reason) {
ArrayList procs = new ArrayList<>();
// Remove all processes this package may have touched: all with the
// same UID (except for the system or root user), and all whose name
// matches the package name.
final int NP = mProcessNames.getMap().size();
for (int ip=0; ip apps = mProcessNames.getMap().valueAt(ip);
final int NA = apps.size();
for (int ia=0; ia= 0 && UserHandle.getAppId(app.uid) != appId) {
continue;
}
// Package has been specified, we want to hit all processes
// that match it. We need to qualify this by the processes
// that are running under the specified app and user ID.
} else {
final boolean isDep = app.pkgDeps != null
&& app.pkgDeps.contains(packageName);
if (!isDep && UserHandle.getAppId(app.uid) != appId) {
continue;
}
if (userId != UserHandle.USER_ALL && app.userId != userId) {
continue;
}
if (!app.pkgList.containsKey(packageName) && !isDep) {
continue;
}
}
// Process has passed all conditions, kill it!
if (!doit) {
return true;
}
//[+LEUI] [REQ][LEUI-8957] [xulei] add
//for support double app
if(mIsRemoveCloneTaskOnly && app.isShadow != true)
continue;
//[+LEUI]end
app.removed = true;
procs.add(app);
}
}
int N = procs.size();
for (int i=0; i 0;
}
那么这个方法是在哪里调用的呢?ActivityManagerService当中一共有四处调用,从这里往上推,没办法找到出处,好吧,那换个方向吧。测试同事的操作是在权限里面不停的切换,那就从设置那里入手吧。系统设置的权限界面对应的是GrantPermissionsActivity,当用户操作权限时,系统响应后,就会回调此类的onPermissionGrantResult方法,好,有了这个入口,先验证一下,在这里加一上句日志,看一下入口是不是在这里:
public void onPermissionGrantResult(String name, boolean granted, boolean doNotAskAgain) {
if(this.isObscuredTouch()) {
this.showOverlayDialog();
this.finish();
} else {
Log.i("GrantPermissionsActivity", "on permission grant result, name = " + name + ", granted = " + granted + ", doNotAskAgain = " + doNotAskAgain);
GrantPermissionsActivity.GroupState groupState = (GrantPermissionsActivity.GroupState)this.mRequestGrantPermissionGroups.get(name);
if(groupState.mGroup != null) {
if(granted) {
groupState.mGroup.grantRuntimePermissions(doNotAskAgain);
groupState.mState = 1;
} else {
groupState.mGroup.revokeRuntimePermissions(doNotAskAgain);
groupState.mState = 2;
}
this.updateGrantResults(groupState.mGroup);
}
if(!this.showNextPermissionGroupGrantRequest()) {
this.setResultAndFinish();
}
}
}
把新编译好的apk push到系统目录当中,reboot,操作一下,看到日志出来了。哈哈哈哈,第一步OK了,入口肯定在这里,好了,继续往下分析。整个方法调用当中,最有可能的就是grantRuntimePermissions和revokeRuntimePermissions两步了,分别进入看一下。groupState.mGroup的类型为AppPermissionGroup,就是当前应用的权限管理组。那就进入AppPermissionGroup类的看一下这两个方法,先看一下grantRuntimePermissions:
public boolean grantRuntimePermissions(boolean fixedByTheUser) {
final boolean isSharedUser = mPackageInfo.sharedUserId != null;
final int uid = mPackageInfo.applicationInfo.uid;
Log.i(TAG, "mAppSupportsRuntimePermissions = " + mAppSupportsRuntimePermissions);
// We toggle permissions only to apps that support runtime
// permissions, otherwise we toggle the app op corresponding
// to the permission if the permission is granted to the app.
for (Permission permission : mPermissions.values()) {
Log.i(TAG, "grant permission, name = " + permission.getName());
if (mAppSupportsRuntimePermissions) {
// Do not touch permissions fixed by the system.
if (permission.isSystemFixed()) {
return false;
}
// Ensure the permission app op enabled before the permission grant.
if (permission.hasAppOp() && !permission.isAppOpAllowed()) {
permission.setAppOpAllowed(true);
mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_ALLOWED);
}
// Grant the permission if needed.
if (!permission.isGranted()) {
permission.setGranted(true);
mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
permission.getName(), mUserHandle);
}
// Update the permission flags.
if (!fixedByTheUser) {
// Now the apps can ask for the permission as the user
// no longer has it fixed in a denied state.
if (permission.isUserFixed() || permission.isUserSet()) {
permission.setUserFixed(false);
permission.setUserSet(true);
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_USER_FIXED
| PackageManager.FLAG_PERMISSION_USER_SET,
0, mUserHandle);
}
}
} else {
// Legacy apps cannot have a not granted permission but just in case.
// Also if the permissions has no corresponding app op, then it is a
// third-party one and we do not offer toggling of such permissions.
if (!permission.isGranted() || !permission.hasAppOp()) {
continue;
}
if (!permission.isAppOpAllowed()) {
permission.setAppOpAllowed(true);
// It this is a shared user we want to enable the app op for all
// packages in the shared user to match the behavior of this
// shared user having a runtime permission.
if (isSharedUser) {
// Enable the app op.
String[] packageNames = mPackageManager.getPackagesForUid(uid);
for (String packageName : packageNames) {
mAppOps.setUidMode(permission.getAppOp(), uid,
AppOpsManager.MODE_ALLOWED);
}
} else {
// Enable the app op.
mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_ALLOWED);
}
// Mark that the permission should not be be granted on upgrade
// when the app begins supporting runtime permissions.
if (permission.shouldRevokeOnUpgrade()) {
permission.setRevokeOnUpgrade(false);
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
0, mUserHandle);
}
// Legacy apps do not know that they have to retry access to a
// resource due to changes in runtime permissions (app ops in this
// case). Therefore, we restart them on app op change, so they
// can pick up the change.
mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
}
}
}
return true;
}
Line 4841: 09-22 10:40:51.854 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.READ_CONTACTS
Line 5596: 09-22 10:40:55.601 I/ActivityManager( 1377): Killing 6593:com.android.capsensorforsar/u0a45, isShadow:false (adj 15): empty #17
Line 5739: 09-22 10:40:57.221 I/AppPermissionGroup( 7163): mAppSupportsRuntimePermissions = true
Line 5740: 09-22 10:40:57.221 I/AppPermissionGroup( 7163): grant permission, name = android.permission.READ_PHONE_STATE
Line 5742: 09-22 10:40:57.223 I/AppPermissionGroup( 7163): grant permission, name = android.permission.CALL_PHONE
Line 5827: 09-22 10:40:57.504 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.READ_PHONE_STATE
Line 5831: 09-22 10:40:57.528 W/ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100
Line 5832: 09-22 10:40:57.528 W/ActivityManager( 1377): killPackageProcessesLocked setAdj:-12, app.setAdj:-100
Line 5833: 09-22 10:40:57.529 W/ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100
Line 5834: 09-22 10:40:57.529 W/ActivityManager( 1377): killPackageProcessesLocked setAdj:-12, app.setAdj:-100
Line 5836: 09-22 10:40:57.529 I/ActivityManager( 1377): Killing 7348:com.letv.android.note/u0a27, isShadow:false (adj 9): permissions revoked
看来我们的分析还是正确的,好了,继续往下,让我们来看看revokeRuntimePermissions方法当中都干了什么:
public boolean revokeRuntimePermissions(boolean fixedByTheUser) {
final boolean isSharedUser = mPackageInfo.sharedUserId != null;
final int uid = mPackageInfo.applicationInfo.uid;
// We toggle permissions only to apps that support runtime
// permissions, otherwise we toggle the app op corresponding
// to the permission if the permission is granted to the app.
for (Permission permission : mPermissions.values()) {
Log.i(TAG, "revoke permission, name = " + permission.getName());
if (mAppSupportsRuntimePermissions) {
// Do not touch permissions fixed by the system.
if (permission.isSystemFixed()) {
return false;
}
// Revoke the permission if needed.
if (permission.isGranted()) {
permission.setGranted(false);
mPackageManager.revokeRuntimePermission(mPackageInfo.packageName,
permission.getName(), mUserHandle);
}
// Update the permission flags.
if (fixedByTheUser) {
// Take a note that the user fixed the permission.
if (permission.isUserSet() || !permission.isUserFixed()) {
permission.setUserSet(false);
permission.setUserFixed(true);
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_USER_SET
| PackageManager.FLAG_PERMISSION_USER_FIXED,
PackageManager.FLAG_PERMISSION_USER_FIXED,
mUserHandle);
}
} else {
if (!permission.isUserSet()) {
permission.setUserSet(true);
// Take a note that the user already chose once.
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_USER_SET,
PackageManager.FLAG_PERMISSION_USER_SET,
mUserHandle);
}
}
} else {
// Legacy apps cannot have a non-granted permission but just in case.
// Also if the permission has no corresponding app op, then it is a
// third-party one and we do not offer toggling of such permissions.
if (!permission.isGranted() || !permission.hasAppOp()) {
continue;
}
if (permission.isAppOpAllowed()) {
permission.setAppOpAllowed(false);
// It this is a shared user we want to enable the app op for all
// packages the the shared user to match the behavior of this
// shared user having a runtime permission.
if (isSharedUser) {
String[] packageNames = mPackageManager.getPackagesForUid(uid);
for (String packageName : packageNames) {
// Disable the app op.
mAppOps.setUidMode(permission.getAppOp(), uid,
AppOpsManager.MODE_IGNORED);
}
} else {
// Disable the app op.
mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_IGNORED);
}
// Mark that the permission should not be granted on upgrade
// when the app begins supporting runtime permissions.
if (!permission.shouldRevokeOnUpgrade()) {
permission.setRevokeOnUpgrade(true);
mPackageManager.updatePermissionFlags(permission.getName(),
mPackageInfo.packageName,
PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE,
mUserHandle);
}
// Disabling an app op may put the app in a situation in which it
// has a handle to state it shouldn't have, so we have to kill the
// app. This matches the revoke runtime permission behavior.
mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
}
}
}
return true;
}
@Override
public void revokeRuntimePermission(String packageName, String permissionName,
UserHandle user) {
try {
mPM.revokeRuntimePermission(packageName, permissionName, user.getIdentifier());
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
}
@Override
public void revokeRuntimePermission(String packageName, String name, int userId) {
if (!sUserManager.exists(userId)) {
Log.e(TAG, "No such user:" + userId);
return;
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
"revokeRuntimePermission");
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
"revokeRuntimePermission");
final int appId;
synchronized (mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
final BasePermission bp = mSettings.mPermissions.get(name);
if (bp == null) {
throw new IllegalArgumentException("Unknown permission: " + name);
}
enforceDeclaredAsUsedAndRuntimeOrDevelopmentPermission(pkg, bp);
SettingBase sb = (SettingBase) pkg.mExtras;
if (sb == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
final PermissionsState permissionsState = sb.getPermissionsState();
final int flags = permissionsState.getPermissionFlags(name, userId);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
throw new SecurityException("Cannot revoke system fixed permission: "
+ name + " for package: " + packageName);
}
if (bp.isDevelopment()) {
// Development permissions must be handled specially, since they are not
// normal runtime permissions. For now they apply to all users.
if (permissionsState.revokeInstallPermission(bp) !=
PermissionsState.PERMISSION_OPERATION_FAILURE) {
scheduleWriteSettingsLocked();
}
return;
}
if (permissionsState.revokeRuntimePermission(bp, userId) ==
PermissionsState.PERMISSION_OPERATION_FAILURE) {
return;
}
mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
// Critical, after this call app should never have the permission.
mSettings.writeRuntimePermissionsForUserLPr(userId, true);
appId = UserHandle.getAppId(pkg.applicationInfo.uid);
}
killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
}
boolean handleAppDiedLocked(ProcessRecord app) {
boolean hasVisibleActivities = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
hasVisibleActivities |= stacks.get(stackNdx).handleAppDiedLocked(app);
}
}
return hasVisibleActivities;
}
Line 6848: 09-22 10:41:03.721 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.WRITE_CALENDAR
Line 7865: 09-22 10:41:09.441 I/AppPermissionGroup( 7163): mAppSupportsRuntimePermissions = true
Line 7866: 09-22 10:41:09.441 I/AppPermissionGroup( 7163): grant permission, name = android.permission.READ_EXTERNAL_STORAGE
Line 7896: 09-22 10:41:09.542 I/AppPermissionGroup( 7163): grant permission, name = android.permission.WRITE_EXTERNAL_STORAGE
Line 7957: 09-22 10:41:10.853 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.READ_EXTERNAL_STORAGE
Line 7961: 09-22 10:41:10.883 W/ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100
Line 7962: 09-22 10:41:10.883 W/ActivityManager( 1377): killPackageProcessesLocked setAdj:-12, app.setAdj:-100
Line 7964: 09-22 10:41:10.883 W/ActivityManager( 1377): killPackageProcessesLocked: minOomAdj = -12, app.setAdj = -100
Line 7965: 09-22 10:41:10.883 W/ActivityManager( 1377): killPackageProcessesLocked setAdj:-12, app.setAdj:-100
Line 7966: 09-22 10:41:10.884 I/ActivityManager( 1377): Killing 7445:com.letv.android.note/u0a27, isShadow:false (adj 9): permissions revoked
Line 7974: 09-22 10:41:11.090 W/ActivityManager( 1377): Force removing ActivityRecord{5e97987 u0 com.letv.android.note/.NoteListActivity, isShadow:false t4}: app died, no saved state
Line 7976: 09-22 10:41:11.095 I/AppPermissionGroup( 7163): revoke permission, name = android.permission.WRITE_EXTERNAL_STORAGE
Line 8581: 09-22 10:41:15.018 I/AppPermissionGroup( 7163): mAppSupportsRuntimePermissions = true
Line 8582: 09-22 10:41:15.018 I/AppPermissionGroup( 7163): grant permission, name = android.permission.GET_ACCOUNTS
Line 8587: 09-22 10:41:15.020 I/AppPermissionGroup( 7163): grant permission, name = android.permission.READ_CONTACTS
Line 8681: 09-22 10:41:15.544 I/AppPermissionGroup( 7163): mAppSupportsRuntimePermissions = true
Line 8682: 09-22 10:41:15.544 I/AppPermissionGroup( 7163): grant permission, name = android.permission.READ_PHONE_STATE
Line 8689: 09-22 10:41:15.545 I/AppPermissionGroup( 7163): grant permission, name = android.permission.CALL_PHONE
Line 8708: 09-22 10:41:15.993 I/AppPermissionGroup( 7163): mAppSupportsRuntimePermissions = true
Line 8709: 09-22 10:41:15.993 I/AppPermissionGroup( 7163): grant permission, name = android.permission.READ_CALENDAR
Line 8714: 09-22 10:41:15.995 I/AppPermissionGroup( 7163): grant permission, name = android.permission.WRITE_CALENDAR
Line 8907: 09-22 10:41:16.542 I/AppPermissionGroup( 7163): mAppSupportsRuntimePermissions = true
Line 8908: 09-22 10:41:16.542 I/AppPermissionGroup( 7163): grant permission, name = android.permission.READ_EXTERNAL_STORAGE
Line 8917: 09-22 10:41:16.560 I/AppPermissionGroup( 7163): grant permission, name = android.permission.WRITE_EXTERNAL_STORAGE
在for循环执行移除的逻辑当中,打印了这句日志:Slog.w(TAG, "Force removing " + r + ": app died, no saved state"),系统强制将我们的窗口销毁了,也没有保存状态,现在整个逻辑清楚了,那么为什么这样的操作,系统要销毁我们的窗口呢?来看一下这里的代码:
boolean removeHistoryRecordsForAppLocked(ProcessRecord app) {
removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities");
removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
"mStoppingActivities");
removeHistoryRecordsForAppLocked(mStackSupervisor.mGoingToSleepActivities, app,
"mGoingToSleepActivities");
removeHistoryRecordsForAppLocked(mStackSupervisor.mWaitingVisibleActivities, app,
"mWaitingVisibleActivities");
removeHistoryRecordsForAppLocked(mStackSupervisor.mFinishingActivities, app,
"mFinishingActivities");
boolean hasVisibleActivities = false;
// Clean out the history list.
int i = numActivities();
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Removing app " + app + " from history with " + i + " entries");
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList activities = mTaskHistory.get(taskNdx).mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
--i;
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Record #" + i + " " + r + ": app=" + r.app);
if (r.app == app) {
if (r.visible) {
hasVisibleActivities = true;
}
final boolean remove;
if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
// Don't currently have state for the activity, or
// it is finishing -- always remove it.
remove = true;
} else if (r.launchCount > 2 &&
r.lastLaunchTime > (SystemClock.uptimeMillis()-60000)) {
// We have launched this activity too many times since it was
// able to run, so give up and remove it.
remove = true;
} else {
// The process may be gone, but the activity lives on!
remove = false;
}
if (remove) {
if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) Slog.i(TAG_ADD_REMOVE,
"Removing activity " + r + " from stack at " + i
+ ": haveState=" + r.haveState
+ " stateNotNeeded=" + r.stateNotNeeded
+ " finishing=" + r.finishing
+ " state=" + r.state + " callers=" + Debug.getCallers(5));
if (!r.finishing) {
Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
r.userId, System.identityHashCode(r),
r.task.taskId, r.shortComponentName,
"proc died without state saved");
if (r.state == ActivityState.RESUMED) {
mService.updateUsageStats(r, false);
}
}
} else {
// We have the current state for this activity, so
// it can be restarted later when needed.
if (DEBUG_ALL) Slog.v(TAG, "Keeping entry, setting app to null");
if (DEBUG_APP) Slog.v(TAG_APP,
"Clearing app during removeHistory for activity " + r);
r.app = null;
r.nowVisible = false;
if (!r.haveState) {
if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
"App died, clearing saved state of " + r);
r.icicle = null;
}
}
cleanUpActivityLocked(r, true, true);
if (remove) {
removeActivityFromHistoryLocked(r, "appDied");
}
}
}
}
return hasVisibleActivities;
}
重复操作,对比日志,非常正确!!!!我靠,好兴奋啊!解决了一下bug,又对系统设置、权限、ActivityManagerService增加了更多的了解,太爽了,测试同事,可以交差了,你的操作触发了系统的策略,导致当前的界面被回收了,哇哈哈哈哈…………
中间的分析还是比较复杂的,也走了不少弯路,不过还好找到最终原因了,framework不像我们的应用,可以直接debug,导致分析效率比较低,卓友们还是需要对系统有更多的了解,遇到问题时才能更得心应手。
好了,本博客就写到这里吧,本人水平有限,写的不好请大家见谅,谢谢!!