publicstatic Resources getSystem(){ synchronized (sSync) { Resources ret = mSystem; if (ret == null) { ret = new Resources(); mSystem = ret; } return ret; } }
它的注释里明确表示 is not affected by Runtime Resource Overlay,似乎我们的问题就这么简单地解决了,只是简单的 API 用错了而已……? 如果 Resources.getSystem() 真的完全不受 RRO 影响,那测试代码应该输出来自 frameworks/base/core/res/res/values/config.xml 的空值而不是来自 RRO 的值。所以问题并没有这么简单,我们继续。
final ArrayList<ParsedConfiguration> overlays = new ArrayList<>(); for (int i = 0, n = partitions.size(); i < n; i++) { final OverlayPartition partition = partitions.get(i); final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get(); final ArrayList<ParsedConfiguration> partitionOverlays = OverlayConfigParser.getConfigurations(partition, scanner, packageManagerOverlayInfos, activeApexesPerPartition.getOrDefault(partition.type, Collections.emptyList())); if (partitionOverlays != null) { overlays.addAll(partitionOverlays); continue; }
final ArrayList<ParsedOverlayInfo> partitionOverlayInfos; if (scannerFactory != null) { partitionOverlayInfos = new ArrayList<>(scanner.getAllParsedInfos()); } else { partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos.values()); for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) { if (!partition.containsFile(partitionOverlayInfos.get(j) .getOriginalPartitionPath())) { partitionOverlayInfos.remove(j); } } }
final ArrayList<ParsedConfiguration> partitionConfigs = new ArrayList<>(); for (int j = 0, m = partitionOverlayInfos.size(); j < m; j++) { final ParsedOverlayInfo p = partitionOverlayInfos.get(j); if (p.isStatic) { partitionConfigs.add(new ParsedConfiguration(p.packageName, true , false , partition.policy, p, null)); } }
for (int i = 0, n = overlays.size(); i < n; i++) { final ParsedConfiguration config = overlays.get(i); mConfigurations.put(config.packageName, new Configuration(config, i)); } }
@VisibleForTesting public ArrayList<IdmapInvocation> getImmutableFrameworkOverlayIdmapInvocations(){ final ArrayList<IdmapInvocation> idmapInvocations = new ArrayList<>(); final ArrayList<Configuration> sortedConfigs = getSortedOverlays(); for (int i = 0, n = sortedConfigs.size(); i < n; i++) { final Configuration overlay = sortedConfigs.get(i); if (overlay.parsedConfig.mutable || !overlay.parsedConfig.enabled || !"android".equals(overlay.parsedConfig.parsedInfo.targetPackageName)) { continue; }
@NonNull Set<UserPackage> registerFabricatedOverlay( @NonNull final FabricatedOverlayInternal overlay) throws OperationFailedException { if (FrameworkParsingPackageUtils.validateName(overlay.overlayName, false , true ) != null) { thrownew OperationFailedException( "overlay name can only consist of alphanumeric characters, '_', and '.'"); }
final FabricatedOverlayInfo info = mIdmapManager.createFabricatedOverlay(overlay); if (info == null) { thrownew OperationFailedException("failed to create fabricated overlay"); }
final Set<UserPackage> updatedTargets = new ArraySet<>(); for (int userId : mSettings.getUsers()) { updatedTargets.addAll(registerFabricatedOverlay(info, userId)); } return updatedTargets; }
final ArraySet<UserPackage> updatedTargets = new ArraySet<>(); final ArrayMap<String, PackageState> userPackages = mPackageManager.initializeForUser( newUserId); CollectionUtils.addAll(updatedTargets, removeOverlaysForUser( (info) -> !userPackages.containsKey(info.packageName), newUserId));
final ArraySet<String> overlaidByOthers = new ArraySet<>(); for (PackageState packageState : userPackages.values()) { var pkg = packageState.getAndroidPackage(); final String overlayTarget = pkg == null ? null : pkg.getOverlayTarget(); if (!TextUtils.isEmpty(overlayTarget)) { overlaidByOthers.add(overlayTarget); } }
for (int i = 0, n = userPackages.size(); i < n; i++) { final PackageState packageState = userPackages.valueAt(i); var pkg = packageState.getAndroidPackage(); if (pkg == null) { continue; }
Status Idmap2Service::acquireFabricatedOverlayIterator(int32_t* _aidl_return) { std::lock_guard l(frro_iter_mutex_); if (frro_iter_.has_value()) { LOG(WARNING) << "active ffro iterator was not previously released"; } frro_iter_ = std::filesystem::directory_iterator(kIdmapCacheDir); if (frro_iter_id_ == std::numeric_limits<int32_t>::max()) { frro_iter_id_ = 0; } else { ++frro_iter_id_; } *_aidl_return = frro_iter_id_; return ok(); }
Status Idmap2Service::nextFabricatedOverlayInfos(int32_t iteratorId, std::vector<os::FabricatedOverlayInfo>* _aidl_return) { std::lock_guard l(frro_iter_mutex_);
constexprsize_t kMaxEntryCount = 100; if (!frro_iter_.has_value()) { return error("no active frro iterator"); } elseif (frro_iter_id_ != iteratorId) { return error("incorrect iterator id in a call to next"); }
if (userId == UserHandle.USER_SYSTEM) { for (int i = 0; i < numberOfPendingChanges; i++) { final String targetPackageName = pendingChanges.keyAt(i); final OverlayPaths newOverlayPaths = pendingChanges.valueAt(i); maybeUpdateSystemOverlays(targetPackageName, newOverlayPaths); } }
@GuardedBy(anyOf = {"mService", "mProcLock"}) voidupdateApplicationInfoLOSP(List<String> packagesToUpdate, int userId, boolean updateFrameworkRes){ final ArrayMap<String, ApplicationInfo> applicationInfoByPackage = new ArrayMap<>(); for (int i = packagesToUpdate.size() - 1; i >= 0; i--) { final String packageName = packagesToUpdate.get(i); final ApplicationInfo ai = mService.getPackageManagerInternal().getApplicationInfo( packageName, STOCK_PM_FLAGS, Process.SYSTEM_UID, userId); if (ai != null) { applicationInfoByPackage.put(packageName, ai); } } mService.mActivityTaskManager.updateActivityApplicationInfo(userId, applicationInfoByPackage);
final ArrayList<WindowProcessController> targetProcesses = new ArrayList<>(); for (int i = mLruProcesses.size() - 1; i >= 0; i--) { final ProcessRecord app = mLruProcesses.get(i); if (app.getThread() == null) { continue; }
final List<String> newPaths = new ArrayList<>(); makePaths(mActivityThread, aInfo, newPaths); final List<String> addedPaths = new ArrayList<>(newPaths.size());
if (oldPaths != null) { for (String path : newPaths) { final String apkName = path.substring(path.lastIndexOf(File.separator)); boolean match = false; for (String oldPath : oldPaths) { final String oldApkName = oldPath.substring(oldPath.lastIndexOf(File.separator)); if (apkName.equals(oldApkName)) { match = true; break; } } if (!match) { addedPaths.add(path); } } } else { addedPaths.addAll(newPaths); } synchronized (mLock) { createOrUpdateClassLoaderLocked(addedPaths); if (mResources != null) { final String[] splitPaths; try { splitPaths = getSplitPaths(null); } catch (NameNotFoundException e) { thrownew AssertionError("null split not found"); }
publicstatic Resources getSystem(){ synchronized (sSync) { Resources ret = mSystem; if (ret == null) { ret = new Resources(); mSystem = ret; } return ret; } }
它的注释里明确表示 is not affected by Runtime Resource Overlay,似乎我们的问题就这么简单地解决了,只是简单的 API 用错了而已……? 如果 Resources.getSystem() 真的完全不受 RRO 影响,那测试代码应该输出来自 frameworks/base/core/res/res/values/config.xml 的空值而不是来自 RRO 的值。所以问题并没有这么简单,我们继续。
final ArrayList<ParsedConfiguration> overlays = new ArrayList<>(); for (int i = 0, n = partitions.size(); i < n; i++) { final OverlayPartition partition = partitions.get(i); final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get(); final ArrayList<ParsedConfiguration> partitionOverlays = OverlayConfigParser.getConfigurations(partition, scanner, packageManagerOverlayInfos, activeApexesPerPartition.getOrDefault(partition.type, Collections.emptyList())); if (partitionOverlays != null) { overlays.addAll(partitionOverlays); continue; }
final ArrayList<ParsedOverlayInfo> partitionOverlayInfos; if (scannerFactory != null) { partitionOverlayInfos = new ArrayList<>(scanner.getAllParsedInfos()); } else { partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos.values()); for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) { if (!partition.containsFile(partitionOverlayInfos.get(j) .getOriginalPartitionPath())) { partitionOverlayInfos.remove(j); } } }
final ArrayList<ParsedConfiguration> partitionConfigs = new ArrayList<>(); for (int j = 0, m = partitionOverlayInfos.size(); j < m; j++) { final ParsedOverlayInfo p = partitionOverlayInfos.get(j); if (p.isStatic) { partitionConfigs.add(new ParsedConfiguration(p.packageName, true , false , partition.policy, p, null)); } }
for (int i = 0, n = overlays.size(); i < n; i++) { final ParsedConfiguration config = overlays.get(i); mConfigurations.put(config.packageName, new Configuration(config, i)); } }
@VisibleForTesting public ArrayList<IdmapInvocation> getImmutableFrameworkOverlayIdmapInvocations(){ final ArrayList<IdmapInvocation> idmapInvocations = new ArrayList<>(); final ArrayList<Configuration> sortedConfigs = getSortedOverlays(); for (int i = 0, n = sortedConfigs.size(); i < n; i++) { final Configuration overlay = sortedConfigs.get(i); if (overlay.parsedConfig.mutable || !overlay.parsedConfig.enabled || !"android".equals(overlay.parsedConfig.parsedInfo.targetPackageName)) { continue; }
@NonNull Set<UserPackage> registerFabricatedOverlay( @NonNull final FabricatedOverlayInternal overlay) throws OperationFailedException { if (FrameworkParsingPackageUtils.validateName(overlay.overlayName, false , true ) != null) { thrownew OperationFailedException( "overlay name can only consist of alphanumeric characters, '_', and '.'"); }
final FabricatedOverlayInfo info = mIdmapManager.createFabricatedOverlay(overlay); if (info == null) { thrownew OperationFailedException("failed to create fabricated overlay"); }
final Set<UserPackage> updatedTargets = new ArraySet<>(); for (int userId : mSettings.getUsers()) { updatedTargets.addAll(registerFabricatedOverlay(info, userId)); } return updatedTargets; }
final ArraySet<UserPackage> updatedTargets = new ArraySet<>(); final ArrayMap<String, PackageState> userPackages = mPackageManager.initializeForUser( newUserId); CollectionUtils.addAll(updatedTargets, removeOverlaysForUser( (info) -> !userPackages.containsKey(info.packageName), newUserId));
final ArraySet<String> overlaidByOthers = new ArraySet<>(); for (PackageState packageState : userPackages.values()) { var pkg = packageState.getAndroidPackage(); final String overlayTarget = pkg == null ? null : pkg.getOverlayTarget(); if (!TextUtils.isEmpty(overlayTarget)) { overlaidByOthers.add(overlayTarget); } }
for (int i = 0, n = userPackages.size(); i < n; i++) { final PackageState packageState = userPackages.valueAt(i); var pkg = packageState.getAndroidPackage(); if (pkg == null) { continue; }
Status Idmap2Service::acquireFabricatedOverlayIterator(int32_t* _aidl_return) { std::lock_guard l(frro_iter_mutex_); if (frro_iter_.has_value()) { LOG(WARNING) << "active ffro iterator was not previously released"; } frro_iter_ = std::filesystem::directory_iterator(kIdmapCacheDir); if (frro_iter_id_ == std::numeric_limits<int32_t>::max()) { frro_iter_id_ = 0; } else { ++frro_iter_id_; } *_aidl_return = frro_iter_id_; return ok(); }
Status Idmap2Service::nextFabricatedOverlayInfos(int32_t iteratorId, std::vector<os::FabricatedOverlayInfo>* _aidl_return) { std::lock_guard l(frro_iter_mutex_);
constexprsize_t kMaxEntryCount = 100; if (!frro_iter_.has_value()) { return error("no active frro iterator"); } elseif (frro_iter_id_ != iteratorId) { return error("incorrect iterator id in a call to next"); }
if (userId == UserHandle.USER_SYSTEM) { for (int i = 0; i < numberOfPendingChanges; i++) { final String targetPackageName = pendingChanges.keyAt(i); final OverlayPaths newOverlayPaths = pendingChanges.valueAt(i); maybeUpdateSystemOverlays(targetPackageName, newOverlayPaths); } }
@GuardedBy(anyOf = {"mService", "mProcLock"}) voidupdateApplicationInfoLOSP(List<String> packagesToUpdate, int userId, boolean updateFrameworkRes){ final ArrayMap<String, ApplicationInfo> applicationInfoByPackage = new ArrayMap<>(); for (int i = packagesToUpdate.size() - 1; i >= 0; i--) { final String packageName = packagesToUpdate.get(i); final ApplicationInfo ai = mService.getPackageManagerInternal().getApplicationInfo( packageName, STOCK_PM_FLAGS, Process.SYSTEM_UID, userId); if (ai != null) { applicationInfoByPackage.put(packageName, ai); } } mService.mActivityTaskManager.updateActivityApplicationInfo(userId, applicationInfoByPackage);
final ArrayList<WindowProcessController> targetProcesses = new ArrayList<>(); for (int i = mLruProcesses.size() - 1; i >= 0; i--) { final ProcessRecord app = mLruProcesses.get(i); if (app.getThread() == null) { continue; }
final List<String> newPaths = new ArrayList<>(); makePaths(mActivityThread, aInfo, newPaths); final List<String> addedPaths = new ArrayList<>(newPaths.size());
if (oldPaths != null) { for (String path : newPaths) { final String apkName = path.substring(path.lastIndexOf(File.separator)); boolean match = false; for (String oldPath : oldPaths) { final String oldApkName = oldPath.substring(oldPath.lastIndexOf(File.separator)); if (apkName.equals(oldApkName)) { match = true; break; } } if (!match) { addedPaths.add(path); } } } else { addedPaths.addAll(newPaths); } synchronized (mLock) { createOrUpdateClassLoaderLocked(addedPaths); if (mResources != null) { final String[] splitPaths; try { splitPaths = getSplitPaths(null); } catch (NameNotFoundException e) { thrownew AssertionError("null split not found"); }