/** * Return a global shared Resources object that provides access to only * system resources (no application resources), is not configured for the * current screen (can not use dimension units, does not change based on * orientation, etc), and is not affected by Runtime Resource Overlay. */ 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 的值。所以问题并没有这么简单,我们继续。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/** * Only for creating the System resources. This is the only constructor that doesn't add * Resources itself to the ResourcesManager list of all Resources references. */ @UnsupportedAppUsage privateResources(){ mClassLoader = ClassLoader.getSystemClassLoader(); sResourcesHistory.add(this);
final DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults();
final Configuration config = new Configuration(); config.setToDefaults();
mResourcesImpl = new ResourcesImpl(AssetManager.getSystem(), metrics, config, new DisplayAdjustments()); }
/** * Return a global shared asset manager that provides access to only * system assets (no application assets). * @hide */ @UnsupportedAppUsage publicstatic AssetManager getSystem(){ synchronized (sSync) { createSystemAssetsInZygoteLocked(false, FRAMEWORK_APK_PATH); return sSystem; } }
/** * This must be called from Zygote so that system assets are shared by all applications. * @hide */ @GuardedBy("sSync") @VisibleForTesting publicstaticvoidcreateSystemAssetsInZygoteLocked(boolean reinitialize, String frameworkPath){ if (sSystem != null && !reinitialize) { return; }
try { final ArrayList<ApkAssets> apkAssets = new ArrayList<>(); apkAssets.add(ApkAssets.loadFromPath(frameworkPath, ApkAssets.PROPERTY_SYSTEM));
// TODO(Ravenwood): overlay support? final String[] systemIdmapPaths = RavenwoodEnvironment.getInstance().isRunningOnRavenwood() ? new String[0] : OverlayConfig.getZygoteInstance().createImmutableFrameworkIdmapsInZygote(); for (String idmapPath : systemIdmapPaths) { apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, ApkAssets.PROPERTY_SYSTEM)); }
sSystemApkAssetsSet = new ArraySet<>(apkAssets); sSystemApkAssets = apkAssets.toArray(new ApkAssets[0]); if (sSystem == null) { sSystem = new AssetManager(true/*sentinel*/); } sSystem.setApkAssets(sSystemApkAssets, false/*invalidateCaches*/); } catch (IOException e) { thrownew IllegalStateException("Failed to create system AssetManager", e); } }
@VisibleForTesting publicOverlayConfig(@Nullable File rootDirectory, @Nullable Supplier<OverlayScanner> scannerFactory, @Nullable PackageProvider packageProvider){ Preconditions.checkArgument((scannerFactory == null) != (packageProvider == null), "scannerFactory and packageProvider cannot be both null or both non-null");
final ArrayList<OverlayPartition> partitions; if (rootDirectory == null) { partitions = new ArrayList<>( PackagePartitions.getOrderedPartitions(OverlayPartition::new)); } else { // Rebase the system partitions and settings file on the specified root directory. partitions = new ArrayList<>(PackagePartitions.getOrderedPartitions( p -> new OverlayPartition( new File(rootDirectory, p.getNonConicalFolder().getPath()), p))); } mIsDefaultPartitionOrder = !sortPartitions(PARTITION_ORDER_FILE_PATH, partitions); mPartitionOrder = generatePartitionOrderString(partitions);
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; }
// If the configuration file is not present, then use android:isStatic and // android:priority to configure the overlays in the partition. // TODO(147840005): Remove converting static overlays to immutable, default-enabled // overlays when android:siStatic and android:priority are fully deprecated. final ArrayList<ParsedOverlayInfo> partitionOverlayInfos; if (scannerFactory != null) { partitionOverlayInfos = new ArrayList<>(scanner.getAllParsedInfos()); } else { // Filter out overlays not present in the partition. partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos.values()); for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) { if (!partition.containsFile(partitionOverlayInfos.get(j) .getOriginalPartitionPath())) { partitionOverlayInfos.remove(j); } } }
// Static overlays are configured as immutable, default-enabled overlays. 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/* enabled */, false/* mutable */, partition.policy, p, null)); } }
for (int i = 0, n = overlays.size(); i < n; i++) { // Add the configurations to a map so definitions of an overlay in an earlier // partition can be replaced by an overlay with the same package name in a later // partition. final ParsedConfiguration config = overlays.get(i); mConfigurations.put(config.packageName, new Configuration(config, i)); } }
/** * Retrieves a list of immutable framework overlays in order of least precedence to greatest * precedence. */ @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; }
// Only enforce that overlays targeting packages with overlayable declarations abide by // those declarations if the target sdk of the overlay is at least Q (when overlayable // was introduced). finalboolean enforceOverlayable = overlay.parsedConfig.parsedInfo.targetSdkVersion >= Build.VERSION_CODES.Q;
// Determine if the idmap for the current overlay can be generated in the last idmap // create-multiple invocation. IdmapInvocation invocation = null; if (!idmapInvocations.isEmpty()) { final IdmapInvocation last = idmapInvocations.get(idmapInvocations.size() - 1); if (last.enforceOverlayable == enforceOverlayable && last.policy.equals(overlay.parsedConfig.policy)) { invocation = last; } }
if (invocation == null) { invocation = new IdmapInvocation(enforceOverlayable, overlay.parsedConfig.policy); idmapInvocations.add(invocation); }
/** * The list of all system partitions that may contain packages in ascending order of * specificity (the more generic, the earlier in the list a partition appears). */ privatestaticfinal ArrayList<SystemPartition> SYSTEM_PARTITIONS = new ArrayList<>(Arrays.asList( new SystemPartition(Environment.getRootDirectory(), PARTITION_SYSTEM, Partition.PARTITION_NAME_SYSTEM, true/* containsPrivApp */, false/* containsOverlay */), // new SystemPartition(Environment.getVendorDirectory(), PARTITION_VENDOR, Partition.PARTITION_NAME_VENDOR, true/* containsPrivApp */, true/* containsOverlay */), new SystemPartition(Environment.getOdmDirectory(), PARTITION_ODM, Partition.PARTITION_NAME_ODM, true/* containsPrivApp */, true/* containsOverlay */), new SystemPartition(Environment.getOemDirectory(), PARTITION_OEM, Partition.PARTITION_NAME_OEM, false/* containsPrivApp */, true/* containsOverlay */), new SystemPartition(Environment.getProductDirectory(), PARTITION_PRODUCT, Partition.PARTITION_NAME_PRODUCT, true/* containsPrivApp */, true/* containsOverlay */), new SystemPartition(Environment.getSystemExtDirectory(), PARTITION_SYSTEM_EXT, Partition.PARTITION_NAME_SYSTEM_EXT, true/* containsPrivApp */, true/* containsOverlay */)));
/** * Recursively searches the directory for overlay APKs. If an overlay is found with the same * package name as a previously scanned overlay, the info of the new overlay will replace the * info of the previously scanned overlay. */ publicvoidscanDir(File partitionOverlayDir){ if (!partitionOverlayDir.exists() || !partitionOverlayDir.isDirectory()) { return; }
if (!partitionOverlayDir.canRead()) { Log.w(TAG, "Directory " + partitionOverlayDir + " cannot be read"); return; }
final File[] files = partitionOverlayDir.listFiles(); if (files == null) { return; }
for (int i = 0; i < files.length; i++) { final File f = files[i]; if (f.isDirectory()) { scanDir(f); }
if (!f.isFile() || !f.getPath().endsWith(".apk")) { continue; }
final ParsedOverlayInfo info = parseOverlayManifest(f, mExcludedOverlayPackages); if (info == null) { continue; }
/** * Load in commonly used resources, so they can be shared across processes. * * These tend to be a few Kbytes, but are frequently in the 20-40K range, and occasionally even * larger. * @hide */ @UnsupportedAppUsage publicstaticvoidpreloadResources(){ try { final Resources sysRes = Resources.getSystem(); sysRes.startPreloading(); if (PRELOAD_RESOURCES) { Log.i(TAG, "Preloading resources...");
long startTime = SystemClock.uptimeMillis(); TypedArray ar = sysRes.obtainTypedArray( com.android.internal.R.array.preloaded_drawables); int numberOfEntries = preloadDrawables(sysRes, ar); ar.recycle(); Log.i(TAG, "...preloaded " + numberOfEntries + " resources in " + (SystemClock.uptimeMillis() - startTime) + "ms.");
@NonNull Set<UserPackage> registerFabricatedOverlay( @NonNull final FabricatedOverlayInternal overlay) throws OperationFailedException { if (FrameworkParsingPackageUtils.validateName(overlay.overlayName, false/* requireSeparator */, true/* requireFilename */) != 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; }
// Generate the file path of the fabricated overlay and ensure it does not collide with an // existing path. Re-registering a fabricated overlay will always result in an updated path. std::string path; std::string file_name; do { constexprsize_t kSuffixLength = 4; conststd::string random_suffix = RandomStringForPath(kSuffixLength); file_name = StringPrintf("%s-%s-%s.frro", overlay.packageName.c_str(), overlay.overlayName.c_str(), random_suffix.c_str()); path = StringPrintf("%s/%s", kIdmapCacheDir.data(), file_name.c_str());
// Invoking std::filesystem::exists with a file name greater than 255 characters will cause this // process to abort since the name exceeds the maximum file name size. constsize_t kMaxFileNameLength = 255; if (file_name.size() > kMaxFileNameLength) { return error( base::StringPrintf("fabricated overlay file name '%s' longer than %zu characters", file_name.c_str(), kMaxFileNameLength)); } } while (std::filesystem::exists(path)); builder.setFrroPath(path);
constuid_t uid = IPCThreadState::self()->getCallingUid(); if (!UidHasWriteAccessToPath(uid, path)) { return error(base::StringPrintf("will not write to %s: calling uid %d lacks write access", path.c_str(), uid)); }
constauto frro = builder.Build(); if (!frro) { return error(StringPrintf("failed to serialize '%s:%s': %s", overlay.packageName.c_str(), overlay.overlayName.c_str(), frro.GetErrorMessage().c_str())); } // Persist the fabricated overlay. umask(kIdmapFilePermissionMask); std::ofstream fout(path); if (fout.fail()) { return error("failed to open frro path " + path); } auto result = frro->ToBinaryStream(fout); if (!result) { unlink(path.c_str()); return error("failed to write to frro path " + path + ": " + result.GetErrorMessage()); } if (fout.fail()) { unlink(path.c_str()); return error("failed to write to frro path " + path); }
/** * Call this to synchronize the Settings for a user with what PackageManager knows about a user. * Returns a list of target packages that must refresh their overlays. This list is the union * of two sets: the set of targets with currently active overlays, and the * set of targets that had, but no longer have, active overlays. */ @NonNull ArraySet<UserPackage> updateOverlaysForUser(finalint newUserId){ if (DEBUG) { Slog.d(TAG, "updateOverlaysForUser newUserId=" + newUserId); }
// Remove the settings of all overlays that are no longer installed for this user. 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); } }
// Update the state of all installed packages containing overlays, and initialize new // overlays that are not currently in the settings. for (int i = 0, n = userPackages.size(); i < n; i++) { final PackageState packageState = userPackages.valueAt(i); var pkg = packageState.getAndroidPackage(); if (pkg == null) { continue; }
// When a new user is switched to for the first time, package manager must be // informed of the overlay paths for all overlaid packages installed in the user. if (overlaidByOthers.contains(packageName)) { updatedTargets.add(UserPackage.of(newUserId, packageName)); } } catch (OperationFailedException e) { Slog.e(TAG, "failed to initialize overlays of '" + packageName + "' for user " + newUserId + "", e); } }
// Update the state of all fabricated overlays, and initialize fabricated overlays in the // new user. for (final FabricatedOverlayInfo info : getFabricatedOverlayInfos()) { try { CollectionUtils.addAll(updatedTargets, registerFabricatedOverlay( info, newUserId)); } catch (OperationFailedException e) { Slog.e(TAG, "failed to initialize fabricated overlay of '" + info.path + "' for user " + newUserId + "", e); } }
// Collect all of the categories in which we have at least one overlay enabled. final ArraySet<String> enabledCategories = new ArraySet<>(); final ArrayMap<String, List<OverlayInfo>> userOverlays = mSettings.getOverlaysForUser(newUserId); finalint userOverlayTargetCount = userOverlays.size(); for (int i = 0; i < userOverlayTargetCount; i++) { final List<OverlayInfo> overlayList = userOverlays.valueAt(i); finalint overlayCount = overlayList != null ? overlayList.size() : 0; for (int j = 0; j < overlayCount; j++) { final OverlayInfo oi = overlayList.get(j); if (oi.isEnabled()) { enabledCategories.add(oi.category); } } }
// Enable the default overlay if its category does not have a single overlay enabled. for (final String defaultOverlay : mDefaultOverlays) { try { // OverlayConfig is the new preferred way to enable overlays by default. This legacy // default enabled method was created before overlays could have a name specified. // Only allow enabling overlays without a name using this mechanism. final OverlayIdentifier overlay = new OverlayIdentifier(defaultOverlay);
final OverlayInfo oi = mSettings.getOverlayInfo(overlay, newUserId); if (!enabledCategories.contains(oi.category)) { Slog.w(TAG, "Enabling default overlay '" + defaultOverlay + "' for target '" + oi.targetPackageName + "' in category '" + oi.category + "' for user " + newUserId); mSettings.setEnabled(overlay, newUserId, true); if (updateState(oi, newUserId, 0)) { CollectionUtils.add(updatedTargets, UserPackage.of(oi.userId, oi.targetPackageName)); } } } catch (OverlayManagerSettings.BadKeyException e) { Slog.e(TAG, "Failed to set default overlay '" + defaultOverlay + "' for user " + newUserId, e); } }
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"); }
/** * Full paths to the locations of extra resource packages (runtime overlays) * this application uses. This field is only used if there are extra resource * packages, otherwise it is null. * * {@hide} */ @UnsupportedAppUsage public String[] resourceDirs;
/** * Contains the contents of {@link #resourceDirs} and along with paths for overlays that may or * may not be APK packages. * * {@hide} */ public String[] overlayPaths;
@UnsupportedAppUsage public Resources getResources(){ if (mResources == null) { final String[] splitPaths; try { splitPaths = getSplitPaths(null); } catch (NameNotFoundException e) { // This should never fail. thrownew AssertionError("null split not found"); }
if (Process.myUid() == mApplicationInfo.uid) { ResourcesManager.getInstance().initializeApplicationPaths(mResDir, splitPaths); }
if (userId == UserHandle.USER_SYSTEM) { // Keep the overlays in the system application info (and anything special cased as well) // up to date to make sure system ui is themed correctly. for (int i = 0; i < numberOfPendingChanges; i++) { final String targetPackageName = pendingChanges.keyAt(i); final OverlayPaths newOverlayPaths = pendingChanges.valueAt(i); maybeUpdateSystemOverlays(targetPackageName, newOverlayPaths); } }
if (updateFrameworkRes) { // Update system server components that need to know about changed overlays. Because the // overlay is applied in ActivityThread, we need to serialize through its thread too. final Executor executor = ActivityThread.currentActivityThread().getExecutor(); final DisplayManagerInternal display = LocalServices.getService(DisplayManagerInternal.class); if (display != null) { executor.execute(display::onOverlayChanged); } if (mWindowManager != null) { executor.execute(mWindowManager::onOverlayChanged); } } }
@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; }
@VisibleForTesting(visibility = PACKAGE) publicvoidhandleApplicationInfoChanged(@NonNull final ApplicationInfo ai){ // Updates triggered by package installation go through a package update // receiver. Here we try to capture ApplicationInfo changes that are // caused by other sources, such as overlays. That means we want to be as conservative // about code changes as possible. Take the diff of the old ApplicationInfo and the new // to see if anything needs to change. LoadedApk apk; LoadedApk resApk; // Update all affected loaded packages with new package information synchronized (mResourcesManager) { WeakReference<LoadedApk> ref = mPackages.get(ai.packageName); apk = ref != null ? ref.get() : null; ref = mResourcePackages.get(ai.packageName); resApk = ref != null ? ref.get() : null; for (ActivityClientRecord ar : mActivities.values()) { if (ar.activityInfo.applicationInfo.packageName.equals(ai.packageName)) { ar.activityInfo.applicationInfo = ai; if (apk != null || resApk != null) { ar.packageInfo = apk != null ? apk : resApk; } else { apk = ar.packageInfo; } } } }
if (apk != null) { final ArrayList<String> oldPaths = new ArrayList<>(); LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths); apk.updateApplicationInfo(ai, oldPaths); } if (resApk != null) { final ArrayList<String> oldPaths = new ArrayList<>(); LoadedApk.makePaths(this, resApk.getApplicationInfo(), oldPaths); resApk.updateApplicationInfo(ai, oldPaths); } if (android.content.res.Flags.systemContextHandleAppInfoChanged() && mSystemThread) { finalvar systemContext = getSystemContext(); if (systemContext.getPackageName().equals(ai.packageName)) { // The system package is not tracked directly, but still needs to receive updates to // its application info. final ArrayList<String> oldPaths = new ArrayList<>(); LoadedApk.makePaths(this, systemContext.getApplicationInfo(), oldPaths); systemContext.mPackageInfo.updateApplicationInfo(ai, oldPaths); } }
synchronized (mResourcesManager) { // Update all affected Resources objects to use new ResourcesImpl mResourcesManager.applyAllPendingAppInfoUpdates(); }
/** * Update the ApplicationInfo for an app. If oldPaths is null, all the paths are considered * new. * @param aInfo The new ApplicationInfo to use for this LoadedApk * @param oldPaths The code paths for the old ApplicationInfo object. null means no paths can * be reused. */ publicvoidupdateApplicationInfo(@NonNull ApplicationInfo aInfo, @Nullable List<String> oldPaths){ if (!setApplicationInfo(aInfo)) { return; }
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) { // This should NEVER fail. thrownew AssertionError("null split not found"); }
/** * Starts the small tangle of critical services that are needed to get the system off the * ground. These services have complex mutual dependencies which is why we initialize them all * in one place here. Unless your service is also entwined in these dependencies, it should be * initialized in one of the other functions. */ privatevoidstartBootstrapServices(@NonNull TimingsTraceAndSlog t){ t.traceBegin("startBootstrapServices"); // ... t.traceBegin("StartPackageManagerService"); try { Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain"); mPackageManagerService = PackageManagerService.main( mSystemContext, installer, domainVerificationService, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF); } finally { Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain"); } // ... // Set up the Application instance for the system process and get started. t.traceBegin("SetSystemProcess"); mActivityManagerService.setSystemProcess(); t.traceEnd(); // Manages Overlay packages t.traceBegin("StartOverlayManagerService"); mSystemServiceManager.startService(new OverlayManagerService(mSystemContext)); t.traceEnd(); t.traceEnd(); // startBootstrapServices }