<?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2008 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); ... --> <permissions> <!-- The following tags are associating low-level group IDs with permission names. By specifying such a mapping, you are saying that any application process granted the given permission will also be running with the given group ID attached to its process, so it can perform any filesystem (read, write, execute) operations allowed for that group. -->
<!-- The group that /cache belongs to, linked to the permission set on the applications that can access /cache --> <permissionname="android.permission.ACCESS_CACHE_FILESYSTEM" > <groupgid="cache" /> </permission>
<!-- RW permissions to any system resources owned by group 'diag'. This is for carrier and manufacture diagnostics tools that must be installable from the framework. Be careful. --> <permissionname="android.permission.DIAGNOSTIC" > <groupgid="input" /> <groupgid="diag" /> </permission>
<!-- Group that can read detailed network usage statistics --> <permissionname="android.permission.READ_NETWORK_USAGE_HISTORY"> <groupgid="net_bw_stats" /> </permission>
<!-- Group that can modify how network statistics are accounted --> <permissionname="android.permission.MODIFY_NETWORK_ACCOUNTING"> <groupgid="net_bw_acct" /> </permission>
<!-- Hotword training apps sometimes need a GID to talk with low-level hardware; give them audio for now until full HAL support is added. --> <permissionname="android.permission.MANAGE_VOICE_KEYPHRASES"> <groupgid="audio" /> </permission>
<permissionname="android.permission.ACCESS_FM_RADIO" > <!-- /dev/fm is gid media, not audio --> <groupgid="media" /> </permission>
<!-- These are permissions that were mapped to gids but we need to keep them here until an upgrade from L to the current version is to be supported. These permissions are built-in and in L were not stored in packages.xml as a result if they are not defined here while parsing packages.xml we would ignore these permissions being granted to apps and not propagate the granted state. From N we are storing the built-in permissions in packages.xml as the saved storage is negligible (one tag with the permission) compared to the fragility as one can remove a built-in permission which no longer needs to be mapped to gids and break grant propagation. --> <permissionname="android.permission.READ_EXTERNAL_STORAGE" /> <permissionname="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- The following tags are assigning high-level permissions to specific user IDs. These are used to allow specific core system users to perform the given operations with the higher-level framework. For example, we give a wide variety of permissions to the shell user since that is the user the adb shell runs under and developers and others should have a fairly open environment in which to interact with the system. -->
<!-- These are the standard packages that are white-listed to always have internet access while in power save mode, even if they aren't in the foreground. --> <!-- 白名单中的应用始终可以访问网络,即使是在省电模式下,且并不在前台也可以 --> <allow-in-power-savepackage="com.android.providers.downloads" />
<!-- These are the standard packages that are white-listed to always have internet access while in data mode, even if they aren't in the foreground. -->
<!-- These are the packages that are white-listed to be able to run as system user --> <system-user-whitelisted-apppackage="com.android.settings" />
<!-- These are the packages that shouldn't run as system user --> <system-user-blacklisted-apppackage="com.android.wallpaper.livepicker" /> </permissions>
if (fname == null) { ..... } elseif (allowed) { //将feature构造成featureInfo,加入到mAvailableFeatures对象中 addFeature(fname, fversion); } ....... } elseif ("unavailable-feature".equals(name) && allowFeatures) { //mUnavailableFeatures保存不支持的feature ......... } elseif ("allow-in-power-save-except-idle".equals(name) && allowAll) { // These are the packages that are white-listed to be able to run in the // background while in power save mode (but not whitelisted from device idle modes), // as read from the configuration files. //mAllowInPowerSaveExceptIdle中保存省电模式下(非Idle),可上网的应用 ......... } elseif ("allow-in-power-save".equals(name) && allowAll) { // These are the packages that are white-listed to be able to run in the // background while in power save mode, as read from the configuration files. //mAllowInPowerSave与mAllowInPowerSaveExceptIdle类似,权限更高 //这与Android M新特性Doze and App Standby模式有关 //DeviceIdleController用于判断设备是否进入Idle状态,进入Idle状态时,mAllowInPowerSaveExceptIdle中的应用要被禁掉 //但mAllowInPowerSave中的应用仍可运行 ............ } elseif ("allow-in-data-usage-save".equals(name) && allowAll) { // These are the packages that are white-listed to be able to run in the // background while in data-usage save mode, as read from the configuration files. //mAllowInDataUsageSave保存此标签对应的packageName //貌似android 7新增了一个节省数据流量的能力,有此标签的应用在节省数据流量时,仍可访问网络 ............ } elseif ("app-link".equals(name) && allowAppConfigs) { // These are the package names of apps which should be in the 'always' // URL-handling state upon factory reset. //mLinkedApps保存此标签对应的packageName //这个不太明白,好像是指定可以一直处于URL-handling state的app ....... } elseif ("system-user-whitelisted-app".equals(name) && allowAppConfigs) { // These are the packages that are whitelisted to be able to run as system user //mSystemUserWhitelistedApps保存此标签对应的packageName //指定以system user权限运行的app ....... } elseif ("system-user-blacklisted-app".equals(name) && allowAppConfigs) { // These are the packages that should not run under system user //mSystemUserBlacklistedApp保存此标签对应的packageName //指定在system user权限下,不应该运行的app ......... }elseif ("default-enabled-vr-app".equals(name) && allowAppConfigs) { // These are the components that are enabled by default as VR mode listener services. //mDefaultVrComponents保存此标签对应的packageName //指定默认运行在VR模式下的components ....... } elseif ("backup-transport-whitelisted-service".equals(name) && allowFeatures) { // These are the permitted backup transport service components //mBackupTransportWhitelist保存此标签对应的packageName //保存能够传输备份数据的服务 ........ } else { ....... } } } catch (XmlPullParserException e) {PullParserException e) { ....... } catch (IOException e) { ....... } finally { IoUtils.closeQuietly(permReader); }
// Some devices can be field-converted to FBE, so offer to splice in // those features if not already defined by the static config //加密相关的feature if (StorageManager.isFileEncryptedNativeOnly()) { addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0); addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0); }
for (String featureName : mUnavailableFeatures) { //从mAvailableFeatures移除不支持的feature removeFeature(featureName); } }
privatevoidfallbackToSingleUserLP() { intflags= UserInfo.FLAG_INITIALIZED; // In split system user mode, the admin and primary flags are assigned to the first human // user. if (!UserManager.isSplitSystemUser()) { flags |= UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY; } // Create the system user UserInfosystem=newUserInfo(UserHandle.USER_SYSTEM, null, null, flags); UserDatauserData=newUserData(); userData.info = system; // 将创建的机主用户加入到mUsers中 synchronized (mUsersLock) { mUsers.put(system.id, userData); } mNextSerialNumber = MIN_USER_ID; mUserVersion = USER_VERSION;
privatevoidremoveUserState(finalint userHandle) { try { // 加密相关. 清除用户的锁屏密码 mContext.getSystemService(StorageManager.class).destroyUserKey(userHandle); } catch (IllegalStateException e) { // This may be simply because the user was partially created. Slog.i(LOG_TAG, "Destroying key for user " + userHandle + " failed, continuing anyway", e); }
// Cleanup gatekeeper secure user id try { finalIGateKeeperServicegk= GateKeeper.getService(); if (gk != null) { // gatekeeper中清除该用户的信息 gk.clearSecureUserId(userHandle); } } catch (Exception ex) { Slog.w(LOG_TAG, "unable to clear GK secure user id"); }
// Clean up all data before removing metadata // 清除用户的数据目录 /data/user_de/<id> /data/user/<id> mPm.destroyUserData(userHandle, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
// Remove this user from the list synchronized (mUsersLock) { mUsers.remove(userHandle); mIsUserManaged.delete(userHandle); } synchronized (mUserStates) { mUserStates.delete(userHandle); } synchronized (mRestrictionsLock) { mBaseUserRestrictions.remove(userHandle); mAppliedUserRestrictions.remove(userHandle); mCachedEffectiveUserRestrictions.remove(userHandle); mDevicePolicyLocalUserRestrictions.remove(userHandle); } // Update the user list synchronized (mPackagesLock) { // 更新 /data/system/users/userlist.xml文件 writeUserListLP(); } // Remove user file AtomicFileuserFile=newAtomicFile(newFile(mUsersDir, userHandle + XML_SUFFIX)); // 最后删除 /data/system/users/<id>.xml userFile.delete(); // 更新mUserIds 数组 updateUserIds(); Slog.i(LOG_TAG, "removeUserState finished! " + userHandle); }
Returns the runtime instruction set corresponding to a given ABI. Multiple compatible ABIs might map to the same instruction set. For example armeabi-v7a and armeabi might map to the instruction set arm. 它描述了应用程序与OS之间的底层接口。ABI涉及了程序的各个方面,比如:目标文件格式、数据类型、数据对齐、函数调用约定以及函数如何传递参数、如何返回值、系统调用号、如何实现系统调用等。
// save off the names of pre-existing system packages prior to scanning; we don't // want to automatically grant runtime permissions for new system apps
// 保存到 mExistingSystemPackages 中,用于install-> runtime if (mPromoteSystemApps) { Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator(); while (pkgSettingIter.hasNext()) { PackageSettingps= pkgSettingIter.next(); // 此处为非用户安装的应用 if (isSystemApp(ps)) { mExistingSystemPackages.add(ps.name); } } }
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr(); for (inti=0; i < deletePkgsList.size(); i++) { // Actual deletion of code and data will be handled by later // reconciliation step finalStringpackageName= deletePkgsList.get(i).name; logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName); synchronized (mPackages) { mSettings.removePackageLPw(packageName); } }
// 删除安装过程中产生的临时文件, vmdl***.tmp文件 deleteTempPackageFiles(); // Remove any shared userIDs that have no associated packages mSettings.pruneSharedUsersLPw();
voidpruneSharedUsersLPw() { ArrayList<String> removeStage = newArrayList<String>(); for (Map.Entry<String,SharedUserSetting> entry : mSharedUsers.entrySet()) { finalSharedUserSettingsus= entry.getValue(); // mSharedUsers 绑定的 SharedUserSetting 为 null, 直接把该shareUser项从mSharedUsers中删除 if (sus == null) { removeStage.add(entry.getKey()); continue; } // remove packages that are no longer installed // 如果当前安装的包中没有 ShareUser关联的包,则删除该关联项. // shareUser可以关联多个包, 单包没有安装,则从shareUser中删除这个关联的单包 for (Iterator<PackageSetting> iter = sus.packages.iterator(); iter.hasNext();) { PackageSettingps= iter.next(); if (mPackages.get(ps.name) == null) { iter.remove(); } } // 如果某个shareUser关联的包列表中的所有项都没有安装,则直接将该shareuser 从mSharedUsers中去除. if (sus.packages.size() == 0) { removeStage.add(entry.getKey()); } } for (inti=0; i < removeStage.size(); i++) { mSharedUsers.remove(removeStage.get(i)); } }
Remove disable package settings for any updated system apps that were removed via an OTA. If they’re not a previously-updated app, remove them completely. Otherwise, just revoke their system-level permissions.
String msg; if (deletedPkg == null) { msg = "Updated system package " + deletedAppName + " no longer exists; it's data will be wiped"; // Actual deletion of code and data will be handled by later // reconciliation step } else { // 在mPakcages中查到了 msg = "Updated system app + " + deletedAppName + " no longer present; removing system privileges for " + deletedAppName;
for (inti=0; i < mExpectingBetter.size(); i++) { finalStringpackageName= mExpectingBetter.keyAt(i); if (!mPackages.containsKey(packageName)) { finalFilescanFile= mExpectingBetter.valueAt(i);
logCriticalInfo(Log.WARN, "Expected better " + packageName + " but never showed up; reverting to system");
//检测pkg的 usesLibraries 和 usesOptionalLibraries 项, 如果其中有lib项,则从mSharedLibraries查找该项,如果没有找到报异常.如果能找到,则将该项的path找到,聚合应用的话,则添加包括 basecodepath splitcodepath ,将这些path更新到 pkg.usesLibraryFiles字段中 updateAllSharedLibrariesLPw(); for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) { // NOTE: We ignore potential failures here during a system scan (like // the rest of the commands above) because there's precious little we // can do about it. A settings error is reported, though. adjustCpuAbisForSharedUserLPw(setting.packages, null/* scanned package */, false/* boot complete */); }
//Used when starting a process for an Activity. publicstaticfinalintNOTIFY_PACKAGE_USE_ACTIVITY=0; //Used when starting a process for a Service. publicstaticfinalintNOTIFY_PACKAGE_USE_SERVICE=1; //Used when moving a Service to the foreground. publicstaticfinalintNOTIFY_PACKAGE_USE_FOREGROUND_SERVICE=2; //Used when starting a process for a BroadcastReceiver. publicstaticfinalintNOTIFY_PACKAGE_USE_BROADCAST_RECEIVER=3; //Used when starting a process for a ContentProvider. publicstaticfinalintNOTIFY_PACKAGE_USE_CONTENT_PROVIDER=4; //Used when starting a process for a BroadcastReceiver. publicstaticfinalintNOTIFY_PACKAGE_USE_BACKUP=5; //Used with Context.getClassLoader() across Android packages. publicstaticfinalintNOTIFY_PACKAGE_USE_CROSS_PACKAGE=6; //Used when starting a package within a process for Instrumentation. publicstaticfinalintNOTIFY_PACKAGE_USE_INSTRUMENTATION=7;
finalbooleanappSupportsRuntimePermissions= pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M; switch (level) { case PermissionInfo.PROTECTION_NORMAL: { // For all apps normal permissions are install time ones. grant = GRANT_INSTALL; } break;
case PermissionInfo.PROTECTION_DANGEROUS: { // If a permission review is required for legacy apps we represent // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. // 如果Build.PERMISSIONS_REVIEW_REQUIRED为true,则肯定不为GRANT_INSTALL类型 // 一般情况下,PERMISSIONS_REVIEW_REQUIRED 不进行设置, 即为false // legacy app ,即 sdk小于M的apk, 在这种情况下,对应dangerous的权限, 授予为安装时权限 if (!appSupportsRuntimePermissions && !Build.PERMISSIONS_REVIEW_REQUIRED) { // For legacy apps dangerous permissions are install time ones. grant = GRANT_INSTALL; } elseif (origPermissions.hasInstallPermission(bp.name)) { // 如果权限已经被赋予了,对应于legacy app 升级为sdk>=M的情况, 类型变为GRANT_UPGRADE // For legacy apps that became modern, install becomes runtime. grant = GRANT_UPGRADE; // 对于从pre-M升级上来的 system app,即使权限没有被赋予, install->runtime } elseif (mPromoteSystemApps && isSystemApp(ps) && mExistingSystemPackages.contains(ps.name)) { // For legacy system apps, install becomes runtime. // We cannot check hasInstallPermission() for system apps since those // permissions were granted implicitly and not persisted pre-M. grant = GRANT_UPGRADE; } else { // For modern apps keep runtime permissions unchanged. grant = GRANT_RUNTIME; } } break;
case PermissionInfo.PROTECTION_SIGNATURE: { // For all apps signature permissions are install time ones. // 进行签名校验,并不只是签名的比对 allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions); if (allowedSig) { grant = GRANT_INSTALL; } } break; }
switch (grant) { case GRANT_INSTALL: { // Revoke this as runtime permission to handle the case of // a runtime permission being downgraded to an install one. // Also in permission review mode we keep dangerous permissions // for legacy apps // runtime权限降级为install权限,需要将runtime权限撤销 for (int userId : UserManagerService.getInstance().getUserIds()) { if (origPermissions.getRuntimePermissionState( bp.name, userId) != null) { // Revoke the runtime permission and clear the flags. origPermissions.revokeRuntimePermission(bp, userId); origPermissions.updatePermissionFlags(bp, userId, PackageManager.MASK_PERMISSION_FLAGS, 0); // If we revoked a permission permission, we have to write. changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } } // Grant an install permission. if (permissionsState.grantInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) { changedInstallPermission = true; } } break;
case GRANT_RUNTIME: { // Grant previously granted runtime permissions. for (int userId : UserManagerService.getInstance().getUserIds()) { PermissionStatepermissionState= origPermissions .getRuntimePermissionState(bp.name, userId); intflags= permissionState != null ? permissionState.getFlags() : 0; // 原来的包中已经由该权限项,不论该权限项是否被授予 if (origPermissions.hasRuntimePermission(bp.name, userId)) { //进行授予权限 if (permissionsState.grantRuntimePermission(bp, userId) == PermissionsState.PERMISSION_OPERATION_FAILURE) { // If we cannot put the permission as it was, we have to write. // 权限未授予成功,才对权限对应xml文件进行更新 changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } // If the app supports runtime permissions no need for a review. // permission Review时,需要更新权限对应xml文件 if (Build.PERMISSIONS_REVIEW_REQUIRED && appSupportsRuntimePermissions && (flags & PackageManager .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; // Since we changed the flags, we have to write. changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } // REVIEW permission Review 且 app版本小于M版本时, 授予运行时权限 // 一般情况下,不在permission review模式下,即该字段不存在 } elseif (Build.PERMISSIONS_REVIEW_REQUIRED && !appSupportsRuntimePermissions) { // For legacy apps that need a permission review, every new // runtime permission is granted but it is pending a review. // We also need to review only platform defined runtime // permissions as these are the only ones the platform knows // how to disable the API to simulate revocation as legacy // apps don't expect to run with revoked permissions. if (PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage)) { if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { flags |= FLAG_PERMISSION_REVIEW_REQUIRED; // We changed the flags, hence have to write. changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } } if (permissionsState.grantRuntimePermission(bp, userId) != PermissionsState.PERMISSION_OPERATION_FAILURE) { // We changed the permission, hence have to write. changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } } // Propagate the permission flags. permissionsState.updatePermissionFlags(bp, userId, flags, flags); } } break;
case GRANT_UPGRADE: { // Grant runtime permissions for a previously held install permission. PermissionStatepermissionState= origPermissions .getInstallPermissionState(bp.name); finalintflags= permissionState != null ? permissionState.getFlags() : 0; // 撤销安装时权限 if (origPermissions.revokeInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) { // We will be transferring the permission flags, so clear them. origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL, PackageManager.MASK_PERMISSION_FLAGS, 0); changedInstallPermission = true; }
// If the permission is not to be promoted to runtime we ignore it and // also its other flags as they are not applicable to install permissions. // install->runtime 的权限在被撤销后会携带FLAG_PERMISSION_REVOKE_ON_UPGRADE的标志, 应用下次升级时,就不会赋予该权限了 if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) { for (int userId : currentUserIds) { // 授予运行时权限 if (permissionsState.grantRuntimePermission(bp, userId) != PermissionsState.PERMISSION_OPERATION_FAILURE) { // Transfer the permission flags. permissionsState.updatePermissionFlags(bp, userId, flags, flags); // If we granted the permission, we have to write. changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } } } } break;
GRANT_DENIED类型,需要撤销安装时权限
1 2 3 4 5 6 7 8 9 10 11 12
if (permissionsState.revokeInstallPermission(bp) != PermissionsState.PERMISSION_OPERATION_FAILURE) { // Also drop the permission flags. permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, PackageManager.MASK_PERMISSION_FLAGS, 0); changedInstallPermission = true; Slog.i(TAG, "Un-granting permission " + perm + " from package " + pkg.packageName + " (protectionLevel=" + bp.protectionLevel + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + ")"); }
最后根据变更权限的user更新权限对应的xml文件
/data/system/users//runtime-permissions.xml
1.4.1.2. 第一次开机或者从pre-M版本升级上来,重设偏好应用
1 2 3 4 5 6 7 8 9 10 11 12
// If this is the first boot or an update from pre-M, and it is a normal // boot, then we need to initialize the default preferred apps across // all defined users. // mPromoteSystemApps 标志pre-M版本升级上来 // mRestoredSettings为false 表明首次开机 if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) { for (UserInfo user : sUserManager.getUsers(true)) { mSettings.applyDefaultPreferredAppsLPw(this, user.id); applyFactoryDefaultBrowserLPw(user.id); primeDomainVerificationsLPw(user.id); } }
1.4.1.3. 调整应用的数据目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14
finalint storageFlags; if (StorageManager.isFileEncryptedNativeOrEmulated()) { // 文件加密模式,只设置DE区 storageFlags = StorageManager.FLAG_STORAGE_DE; } else { // 非文件加密模式, 同时设置DE区和CE区 storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } // Destroys app data that isn't expected, either due to uninstallation or reinstallation on another volume. // 然后,为已安装该应用的用户准备数据目录,包括设置权限及设置selinux标签 // /data/user_de/<userid>/** // /data/user/<userid>/** reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM, storageFlags);
1.4.1.4. 当监测到为升级场景时,需要删除原来包的code_cache
携带了Installer.FLAG_CLEAR_CODE_CACHE_ONLY的flag
1 2 3 4 5 6 7 8 9 10 11 12 13 14
if (mIsUpgrade && !onlyCore) { Slog.i(TAG, "Build fingerprint changed; clearing code caches"); for (inti=0; i < mSettings.mPackages.size(); i++) { finalPackageSettingps= mSettings.mPackages.valueAt(i); if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) { // No apps are running this early, so no need to freeze clearAppDataLIF(ps.pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE // 只清除codecache目录 | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); } } ver.fingerprint = Build.FINGERPRINT; }
1.4.1.5. 更新完应用权限,且偏好应用更新完时,重置某些字段并写入packages.xml
在这个地方会对packages.xml文件进行写入更新
1 2 3 4 5 6 7 8 9 10 11
// clear only after permissions and other defaults have been updated // 该字段用于保存install->runtime的权限 mExistingSystemPackages.clear(); mPromoteSystemApps = false;
// All the changes are done during package scanning. ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
// can downgrade to reader 将上述扫描的结果写入packages.xml mSettings.writeLPr();
final ArraySet<File> unclaimedIcons = newArraySet( mSessionsDir.listFiles());
// Ignore stages and icons claimed by active sessions for (inti=0; i < mSessions.size(); i++) { finalPackageInstallerSessionsession= mSessions.valueAt(i); unclaimedIcons.remove(buildAppIconFile(session.sessionId)); }