// Set flag to monitor and not change apk file paths when // scanning install directories. finalint scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;
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 { msg = "Updated system app + " + deletedAppName + " no longer present; removing system privileges for " + deletedAppName;
// 确保所有在用户 data 分区的应用都显示出来了,如果 data 分区的无法显示,就显示 system 分区的! for (int i = 0; i < mExpectingBetter.size(); i++) { final String packageName = mExpectingBetter.keyAt(i);
// 如果 PMS 仍然没有扫描到 mExpectingBetter 列表中的 apk,说明 data 分区的 apk 无法显示 // 那就要显示原来 system 分区的 apk! if (!mPackages.containsKey(packageName)) { final File scanFile = mExpectingBetter.valueAt(i);
logCriticalInfo(Log.WARN, "Expected better " + packageName + " but never showed up; reverting to system");
} else { // Should not happen at all. Just log an error. Slog.e(TAG, "Resource path not set for package " + pkg.packageName); } } else { resourcePath = pkg.codePath; baseResourcePath = pkg.baseCodePath;
final File scanFile = new File(pkg.codePath); if (pkg.applicationInfo.getCodePath() == null || pkg.applicationInfo.getResourcePath() == null) {
thrownew PackageManagerException(INSTALL_FAILED_INVALID_APK, "Code and resource paths haven't been set correctly"); } //【×】扫描 data 分区不会进入这里,那么 package 也就不会被设置 ApplicationInfo.FLAG_SYSTEM 标志位! if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; if (pkg.applicationInfo.isDirectBootAware()) {
for (PackageParser.Service s : pkg.services) { s.info.encryptionAware = s.info.directBootAware = true; } for (PackageParser.Provider p : pkg.providers) { p.info.encryptionAware = p.info.directBootAware = true; } for (PackageParser.Activity a : pkg.activities) { a.info.encryptionAware = a.info.directBootAware = true; } for (PackageParser.Activity r : pkg.receivers) { r.info.encryptionAware = r.info.directBootAware = true; } } } else { //【×】data 分区 apk 进入这个分支,coreApp 的值为 false,并清除一些 flag; pkg.coreApp = false; pkg.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; pkg.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; }
// 下面这部分扫描 data 分区也不会遇到! pkg.mTrustedOverlay = (policyFlags&PackageParser.PARSE_TRUSTED_OVERLAY) != 0;
if ((policyFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) { pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; }
if ((policyFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) { enforceCodePolicy(pkg); }
if (mCustomResolverComponentName != null && mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) { setUpCustomResolverActivity(pkg); }
// 扫描 data 不会进入这里!! if (pkg.packageName.equals("android")) { ... ... ... ... }
if (DEBUG_PACKAGE_SCANNING) { if ((policyFlags & PackageParser.PARSE_CHATTY) != 0) Log.d(TAG, "Scanning package " + pkg.packageName); }
// Getting the package setting may have a side-effect, so if we // are only checking if scan would succeed, stash a copy of the // old setting to restore at the end. PackageSetting nonMutatedPs = null;
// 非系统 apk 无源包,不进入这个分支! // 覆盖安装的系统 apk,可以进入这个分支,这里的目的是找到合适的源包,用来设置包名,已经复用源包的数据! PackageSetting origPackage = null; String realName = null; if (pkg.mOriginalPackages != null) { final String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage); if (pkg.mOriginalPackages.contains(renamed)) { realName = pkg.mRealPackage; if (!pkg.packageName.equals(renamed)) { pkg.setPackageName(renamed); }
} else {
for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) { if ((origPackage = mSettings.peekPackageLPr( pkg.mOriginalPackages.get(i))) != null) { if (!verifyPackageUpdateLPr(origPackage, pkg)) { // New package is not compatible with original. origPackage = null; continue; } elseif (origPackage.sharedUser != null) { if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) { Slog.w(TAG, "Unable to migrate data from " + origPackage.name + " to " + pkg.packageName + ": old uid " + origPackage.sharedUser.name + " differs from " + pkg.mSharedUserId); origPackage = null; continue; } // TODO: Add case when shared user id is added [b/28144775] } else { if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package " + pkg.packageName + " to old name " + origPackage.name); } break; } } } }
if (mTransferedPackages.contains(pkg.packageName)) { Slog.w(TAG, "Package " + pkg.packageName + " was transferred to another, but its .apk remains"); }
// This package wants to adopt ownership of permissions from // another package. for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) { final String origName = pkg.mAdoptPermissions.get(i); final PackageSetting orig = mSettings.peekPackageLPr(origName); if (orig != null) { if (verifyPackageUpdateLPr(orig, pkg)) { Slog.i(TAG, "Adopting permissions from " + origName + " to " + pkg.packageName);
// 处理特权 apk 的子包,只有特权 apk 才能添加子包; // 特权 apk 包括两部分: // 1、特定 uid 的 app // 2、framework-res.apk 和 system/priv-app 目录下的 apk! if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) { if ((policyFlags & PARSE_IS_PRIVILEGED) == 0) { thrownew PackageManagerException("Only privileged apps and updated " + "privileged apps can add child packages. Ignoring package " + pkg.packageName); } finalint childCount = pkg.childPackages.size(); for (int i = 0; i < childCount; i++) { PackageParser.Package childPkg = pkg.childPackages.get(i); if (mSettings.hasOtherDisabledSystemPkgWithChildLPr(pkg.packageName, childPkg.packageName)) { thrownew PackageManagerException("Cannot override a child package of " + "another disabled system app. Ignoring package " + pkg.packageName); } } }
synchronized (mPackages) { if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
// 如果是系统 package,并且他之前更新过,就要尝试对共享库 lib 进行更新! // 只有系统 package 才能添加共享 lib if (pkg.libraryNames != null) { for (int i=0; i<pkg.libraryNames.size(); i++) { String name = pkg.libraryNames.get(i); boolean allowed = false; if (pkg.isUpdatedSystemApp()) { // New library entries can only be added through the // system image. This is important to get rid of a lot // of nasty edge cases: for example if we allowed a non- // system update of the app to add a library, then uninstalling // the update would make the library go away, and assumptions // we made such as through app install filtering would now // have allowed apps on the device which aren't compatible // with it. Better to just have the restriction here, be // conservative, and create many fewer cases that can negatively // impact the user experience. final PackageSetting sysPs = mSettings .getDisabledSystemPkgLPr(pkg.packageName); if (sysPs.pkg != null && sysPs.pkg.libraryNames != null) { for (int j=0; j<sysPs.pkg.libraryNames.size(); j++) { if (name.equals(sysPs.pkg.libraryNames.get(j))) { allowed = true; break; } } } } else { allowed = true; } if (allowed) { if (!mSharedLibraries.containsKey(name)) { mSharedLibraries.put(name, new SharedLibraryEntry(null, pkg.packageName)); } elseif (!name.equals(pkg.packageName)) { Slog.w(TAG, "Package " + pkg.packageName + " library " + name + " already exists; skipping"); } } else { Slog.w(TAG, "Package " + pkg.packageName + " declares lib " + name + " that is not declared on system image; skipping"); } } if ((scanFlags & SCAN_BOOTING) == 0) {
// If we are not booting, we need to update any applications // that are clients of our shared library. If we are booting, // this will all be done once the scan is complete. clientLibPkgs = updateAllSharedLibrariesLPw(pkg); } } } }
// We don't expect installation to fail beyond this point if (pkgSetting.pkg != null) {
// Note that |user| might be null during the initial boot scan. If a codePath // for an app has changed during a boot scan, it's due to an app update that's // part of the system partition and marker changes must be applied to all users. maybeRenameForeignDexMarkers(pkgSetting.pkg, pkg, (user != null) ? user : UserHandle.ALL); }
//【×】将新创建的 PackageSetting 添加到 mSettings 中! mSettings.insertPackageSettingLPw(pkgSetting, pkg); // 将新创建的 PackageSetting 添加到 PMS.mPackages 中! mPackages.put(pkg.applicationInfo.packageName, pkg); // 将当前的 package 从 mSettings.mPackagesToBeCleaned 中移除,防止数据清除! final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator(); while (iter.hasNext()) { PackageCleanItem item = iter.next(); if (pkgName.equals(item.packageName)) { iter.remove(); } }
// 处理 package 的第一次安装时间和最近更新时间! if (currentTime != 0) { if (pkgSetting.firstInstallTime == 0) { pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
} } elseif (pkgSetting.firstInstallTime == 0) { // We need *something*. Take time time stamp of the file. pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime; } elseif ((policyFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { if (scanFileTime != pkgSetting.timeStamp) {
// A package on the system image has changed; consider this // to be an update. pkgSetting.lastUpdateTime = scanFileTime; } }
// Add the package's KeySets to the global KeySetManagerService ksms.addScannedPackageLPw(pkg); // 处理该 Package 中 的 Provider 信息,添加到 mProviders 中! int N = pkg.providers.size(); StringBuilder r = null; int i; for (i=0; i<N; i++) { PackageParser.Provider p = pkg.providers.get(i); p.info.processName = fixProcessName(pkg.applicationInfo.processName, p.info.processName, pkg.applicationInfo.uid); mProviders.addProvider(p); p.syncable = p.info.isSyncable; if (p.info.authority != null) { String names[] = p.info.authority.split(";"); p.info.authority = null; for (int j = 0; j < names.length; j++) { if (j == 1 && p.syncable) { // We only want the first authority for a provider to possibly be // syncable, so if we already added this provider using a different // authority clear the syncable flag. We copy the provider before // changing it because the mProviders object contains a reference // to a provider that we don't want to change. // Only do this for the second authority since the resulting provider // object can be the same for all future authorities for this provider. p = new PackageParser.Provider(p); p.syncable = false; } if (!mProvidersByAuthority.containsKey(names[j])) { mProvidersByAuthority.put(names[j], p); if (p.info.authority == null) { p.info.authority = names[j]; } else { p.info.authority = p.info.authority + ";" + names[j]; } if (DEBUG_PACKAGE_SCANNING) { if ((policyFlags & PackageParser.PARSE_CHATTY) != 0) Log.d(TAG, "Registered content provider: " + names[j] + ", className = " + p.info.name + ", isSyncable = " + p.info.isSyncable); } } else { PackageParser.Provider other = mProvidersByAuthority.get(names[j]); Slog.w(TAG, "Skipping provider name " + names[j] + " (in package " + pkg.applicationInfo.packageName + "): name already used by " + ((other != null && other.getComponentName() != null) ? other.getComponentName().getPackageName() : "?")); } } } if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(p.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Providers: " + r); }
// 处理该 Package 中的 Service 信息,添加到 PMS.mService 中! N = pkg.services.size(); r = null; for (i=0; i<N; i++) { PackageParser.Service s = pkg.services.get(i); s.info.processName = fixProcessName(pkg.applicationInfo.processName, s.info.processName, pkg.applicationInfo.uid); mServices.addService(s); if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(s.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Services: " + r); }
// 处理该 Package 中的 BroadcastReceiver 信息,添加到 PMS.mReceivers 中。 N = pkg.receivers.size(); r = null; for (i=0; i<N; i++) { PackageParser.Activity a = pkg.receivers.get(i); a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mReceivers.addActivity(a, "receiver"); if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(a.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r); } // 处理该 Package 中的 activity 信息,添加到 PMS.mActivities 中! N = pkg.activities.size(); r = null; for (i=0; i<N; i++) { PackageParser.Activity a = pkg.activities.get(i); a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mActivities.addActivity(a, "activity"); if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(a.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r); }
// 处理该 Package 中的 PermissionGroups 信息 N = pkg.permissionGroups.size(); r = null; for (i=0; i<N; i++) { PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i); PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name); final String curPackageName = cur == null ? null : cur.info.packageName; finalboolean isPackageUpdate = pg.info.packageName.equals(curPackageName); if (cur == null || isPackageUpdate) { mPermissionGroups.put(pg.info.name, pg); if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } if (isPackageUpdate) { r.append("UPD:"); } r.append(pg.info.name); } } else { Slog.w(TAG, "Permission group " + pg.info.name + " from package " + pg.info.packageName + " ignored: original from " + cur.info.packageName); if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append("DUP:"); r.append(pg.info.name); } } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permission Groups: " + r); } // 处理该 Package 中的 Permissions 信息! N = pkg.permissions.size(); r = null; for (i=0; i<N; i++) { PackageParser.Permission p = pkg.permissions.get(i);
// Assume by default that we did not install this permission into the system. p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;
// Now that permission groups have a special meaning, we ignore permission // groups for legacy apps to prevent unexpected behavior. In particular, // permissions for one app being granted to someone just becase they happen // to be in a group defined by another app (before this had no implications). if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { p.group = mPermissionGroups.get(p.info.group); // Warn for a permission in an unknown group. if (p.info.group != null && p.group == null) { Slog.w(TAG, "Permission " + p.info.name + " from package " + p.info.packageName + " in an unknown group " + p.info.group); } }
// 获得 package 的权限对应的 BasePermission 对象! BasePermission bp = permissionMap.get(p.info.name);
// Allow system apps to redefine non-system permissions // BasePermission 不为 null,且当前解析的 package 也不是权限的定义者! if (bp != null && !Objects.equals(bp.sourcePackage, p.info.packageName)) { finalboolean currentOwnerIsSystem = (bp.perm != null && isSystemApp(bp.perm.owner)); if (isSystemApp(p.owner)) // 如果当前 package 申请的权限拥有者是系统 app if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) { // It's a built-in permission and no owner, take ownership now bp.packageSetting = pkgSetting; bp.perm = p; bp.uid = pkg.applicationInfo.uid; bp.sourcePackage = p.info.packageName; p.info.flags |= PermissionInfo.FLAG_INSTALLED; } elseif (!currentOwnerIsSystem) { String msg = "New decl " + p.owner + " of permission " + p.info.name + " is system; overriding " + bp.sourcePackage; reportSettingsProblem(Log.WARN, msg); bp = null; } } }
if (bp == null) { bp = new BasePermission(p.info.name, p.info.packageName, BasePermission.TYPE_NORMAL); permissionMap.put(p.info.name, bp); }
if (bp.perm == null) { if (bp.sourcePackage == null || bp.sourcePackage.equals(p.info.packageName)) { BasePermission tree = findPermissionTreeLP(p.info.name); if (tree == null || tree.sourcePackage.equals(p.info.packageName)) { bp.packageSetting = pkgSetting; bp.perm = p; bp.uid = pkg.applicationInfo.uid; bp.sourcePackage = p.info.packageName; p.info.flags |= PermissionInfo.FLAG_INSTALLED; if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(p.info.name); } } else { Slog.w(TAG, "Permission " + p.info.name + " from package " + p.info.packageName + " ignored: base tree " + tree.name + " is from package " + tree.sourcePackage); } } else { Slog.w(TAG, "Permission " + p.info.name + " from package " + p.info.packageName + " ignored: original from " + bp.sourcePackage); } } elseif ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append("DUP:"); r.append(p.info.name); } if (bp.perm == p) { bp.protectionLevel = p.info.protectionLevel; } }
if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permissions: " + r); }
N = pkg.instrumentation.size(); r = null; for (i=0; i<N; i++) { PackageParser.Instrumentation a = pkg.instrumentation.get(i); a.info.packageName = pkg.applicationInfo.packageName; a.info.sourceDir = pkg.applicationInfo.sourceDir; a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir; a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs; a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs; a.info.dataDir = pkg.applicationInfo.dataDir; a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir; a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir; a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir; mInstrumentation.put(a.getComponentName(), a); if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(a.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r); } // 处理该 Package 中的 protectedBroadcasts 信息! if (pkg.protectedBroadcasts != null) { N = pkg.protectedBroadcasts.size(); for (i=0; i<N; i++) { mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i)); } }
pkgSetting.setTimeStamp(scanFileTime);
// Create idmap files for pairs of (packages, overlay packages). // Note: "android", ie framework-res.apk, is handled by native layers. if (pkg.mOverlayTarget != null) { // This is an overlay package. if (pkg.mOverlayTarget != null && !pkg.mOverlayTarget.equals("android")) { if (!mOverlays.containsKey(pkg.mOverlayTarget)) { mOverlays.put(pkg.mOverlayTarget, new ArrayMap<String, PackageParser.Package>()); } ArrayMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget); map.put(pkg.packageName, pkg); PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget); if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) { createIdmapFailed = true; } } } elseif (mOverlays.containsKey(pkg.packageName) && !pkg.packageName.equals("android")) { // This is a regular package, with one or more known overlay packages. createIdmapsForPackageLI(pkg); } }
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
if (createIdmapFailed) { thrownew PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "scanPackageLI failed to createIdmap"); } return pkg; }
// 最终进入这个方法! private PackageSetting getPackageLPw(String name, PackageSetting origPackage, String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, int vc, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean add, boolean allowInstall, String parentPackage, List<String> childPackageNames){ // 尝试获得之前的安装数据! // 如果是非系统 apk,这个安装就是他自身的;如果是覆盖安装的系统 app,那么这个数据是 data 分区下的; PackageSetting p = mPackages.get(name); UserManagerService userManager = UserManagerService.getInstance(); //【×】如果 p 不为 null,说明这个 data 分区的 apk 之前就存在,它可能是一个非系统 apk; // 也可能是一个系统的 apk 覆盖安装到了 data 分区! if (p != null) { p.primaryCpuAbiString = primaryCpuAbiString; p.secondaryCpuAbiString = secondaryCpuAbiString; if (childPackageNames != null) { p.childPackageNames = new ArrayList<>(childPackageNames); }
// 对于扫描 data 分区的情况,如果 codePath 不匹配,会在【1.3】【B】的位置抛出异常,也就是说会忽略掉这个包! // 这里是不会进入的!! if (!p.codePath.equals(codePath)) { if ((p.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) { Slog.w(PackageManagerService.TAG, "Trying to update system app code path from " + p.codePathString + " to " + codePath.toString()); } else { Slog.i(PackageManagerService.TAG, "Package " + name + " codePath changed from " + p.codePath + " to " + codePath + "; Retaining data and using new");
if (p.appId < 0) { PackageManagerService.reportSettingsProblem(Log.WARN, "Package " + name + " could not be assigned a valid uid"); returnnull; }
if (add) { // add 为 false,这里不添加,添加的操作在 PMS.scanPackageDirtyLI 方法中! addPackageSettingLPw(p, name, sharedUser); } } else { if (installUser != null && allowInstall) { // The caller has explicitly specified the user they want this // package installed for, and the package already exists. // Make sure it conforms to the new request. List<UserInfo> users = getAllUsers(); if (users != null) { for (UserInfo user : users) { if ((installUser.getIdentifier() == UserHandle.USER_ALL && !isAdbInstallDisallowed(userManager, user.id)) || installUser.getIdentifier() == user.id) { boolean installed = p.getInstalled(user.id); if (!installed) { p.setInstalled(true, user.id); writePackageRestrictionsLPr(user.id); } } } } } } // 返回查到或者是创建的新的系统 package 对应的 PackageSetting 对象! return p; }
//【2】确保所有在用户 data 分区的应用都显示出来了,如果 data 分区的无法显示,就显示 system 分区的! for (int i = 0; i < mExpectingBetter.size(); i++) { final String packageName = mExpectingBetter.keyAt(i); // 如果 PMS 仍然没有扫描到 mExpectingBetter 列表中的 apk,说明 data 分区的 apk 无法显示 // 那就要显示原来 system 分区的 apk! if (!mPackages.containsKey(packageName)) { final File scanFile = mExpectingBetter.valueAt(i);
publicPackageStats(String packageName){ this.packageName = packageName; // We expect at least one element in here, but let's make it minimal. compileTimePerCodePath = new ArrayMap<>(2); }