diff options
4 files changed, 117 insertions, 50 deletions
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 248a2f6301cd..8018c2b7c27d 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -25,10 +25,12 @@ import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.os.FileUtils; import android.os.PowerManager; +import android.os.Process; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; +import android.os.storage.StorageManager; import android.util.Log; import android.util.Slog; @@ -148,6 +150,51 @@ public class PackageDexOptimizer { } } + int performDexOpt(SharedLibraryInfo info, String[] instructionSets, DexoptOptions options) { + String classLoaderContext = DexoptUtils.getClassLoaderContext(info); + final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); + String compilerFilter = PackageManagerServiceCompilerMapping.getCompilerFilterForReason( + PackageManagerService.REASON_SHARED); + int result = DEX_OPT_SKIPPED; + for (String instructionSet : dexCodeInstructionSets) { + int dexoptNeeded = getDexoptNeeded( + info.getPath(), instructionSet, compilerFilter, + classLoaderContext, false /* newProfile */, + false /* downgrade */); + if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) { + continue; + } + // Special string recognized by installd. + final String packageName = "*"; + final String outputPath = null; + int dexFlags = DEXOPT_PUBLIC + | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0) + | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0); + dexFlags = adjustDexoptFlags(dexFlags); + final String uuid = StorageManager.UUID_SYSTEM; + final String seInfo = null; + final int targetSdkVersion = 0; // Builtin libraries targets the system's SDK version + try { + mInstaller.dexopt(info.getPath(), Process.SYSTEM_UID, packageName, + instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter, + uuid, classLoaderContext, seInfo, false /* downgrade */, + targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null, + getReasonName(options.getCompilationReason())); + // The end result is: + // - FAILED if any path failed, + // - PERFORMED if at least one path needed compilation, + // - SKIPPED when all paths are up to date + if (result != DEX_OPT_FAILED) { + result = DEX_OPT_PERFORMED; + } + } catch (InstallerException e) { + Slog.w(TAG, "Failed to dexopt", e); + result = DEX_OPT_FAILED; + } + } + return result; + } + /** * Performs dexopt on all code paths of the given package. * It assumes the install lock is held. diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 96441c5f7d18..a98e2d3fd0da 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9443,18 +9443,27 @@ public class PackageManagerService extends IPackageManager.Stub // at boot, or background job), the passed 'targetCompilerFilter' stays the same, // and the first package that uses the library will dexopt it. The // others will see that the compiled code for the library is up to date. - Collection<PackageParser.Package> deps = findSharedNonSystemLibraries(p); + Collection<SharedLibraryInfo> deps = findSharedLibraries(p); final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo); if (!deps.isEmpty()) { DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(), options.getCompilationReason(), options.getCompilerFilter(), options.getSplitName(), options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY); - for (PackageParser.Package depPackage : deps) { - // TODO: Analyze and investigate if we (should) profile libraries. - pdo.performDexOpt(depPackage, instructionSets, - getOrCreateCompilerPackageStats(depPackage), - mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), libraryOptions); + for (SharedLibraryInfo info : deps) { + PackageParser.Package depPackage = null; + synchronized (mPackages) { + depPackage = mPackages.get(info.getPackageName()); + } + if (depPackage != null) { + // TODO: Analyze and investigate if we (should) profile libraries. + pdo.performDexOpt(depPackage, instructionSets, + getOrCreateCompilerPackageStats(depPackage), + mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), + libraryOptions); + } else { + pdo.performDexOpt(info, instructionSets, libraryOptions); + } } } return pdo.performDexOpt(p, instructionSets, @@ -9494,63 +9503,48 @@ public class PackageManagerService extends IPackageManager.Stub return BackgroundDexOptService.runIdleOptimizationsNow(this, mContext, packageNames); } - List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) { - if (p.usesLibraries != null || p.usesOptionalLibraries != null - || p.usesStaticLibraries != null) { - ArrayList<PackageParser.Package> retValue = new ArrayList<>(); + private static List<SharedLibraryInfo> findSharedLibraries(PackageParser.Package p) { + if (p.usesLibraryInfos != null) { + ArrayList<SharedLibraryInfo> retValue = new ArrayList<>(); Set<String> collectedNames = new HashSet<>(); - findSharedNonSystemLibrariesRecursive(p, retValue, collectedNames); - - retValue.remove(p); - + for (SharedLibraryInfo info : p.usesLibraryInfos) { + findSharedLibrariesRecursive(info, retValue, collectedNames); + } return retValue; } else { return Collections.emptyList(); } } - private void findSharedNonSystemLibrariesRecursive(PackageParser.Package p, - ArrayList<PackageParser.Package> collected, Set<String> collectedNames) { - if (!collectedNames.contains(p.packageName)) { - collectedNames.add(p.packageName); - collected.add(p); - - if (p.usesLibraries != null) { - findSharedNonSystemLibrariesRecursive(p.usesLibraries, - null, collected, collectedNames); - } - if (p.usesOptionalLibraries != null) { - findSharedNonSystemLibrariesRecursive(p.usesOptionalLibraries, - null, collected, collectedNames); - } - if (p.usesStaticLibraries != null) { - findSharedNonSystemLibrariesRecursive(p.usesStaticLibraries, - p.usesStaticLibrariesVersions, collected, collectedNames); - } - } - } + private static void findSharedLibrariesRecursive(SharedLibraryInfo info, + ArrayList<SharedLibraryInfo> collected, Set<String> collectedNames) { + if (!collectedNames.contains(info.getName())) { + collectedNames.add(info.getName()); + collected.add(info); - private void findSharedNonSystemLibrariesRecursive(ArrayList<String> libs, long[] versions, - ArrayList<PackageParser.Package> collected, Set<String> collectedNames) { - final int libNameCount = libs.size(); - for (int i = 0; i < libNameCount; i++) { - String libName = libs.get(i); - long version = (versions != null && versions.length == libNameCount) - ? versions[i] : PackageManager.VERSION_CODE_HIGHEST; - PackageParser.Package libPkg = findSharedNonSystemLibrary(libName, version); - if (libPkg != null) { - findSharedNonSystemLibrariesRecursive(libPkg, collected, collectedNames); + if (info.getDependencies() != null) { + for (SharedLibraryInfo dep : info.getDependencies()) { + findSharedLibrariesRecursive(dep, collected, collectedNames); + } } } } - private PackageParser.Package findSharedNonSystemLibrary(String name, long version) { - synchronized (mPackages) { - SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(name, version); - if (libraryInfo != null) { - return mPackages.get(libraryInfo.getPackageName()); + List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package pkg) { + List<SharedLibraryInfo> deps = findSharedLibraries(pkg); + if (!deps.isEmpty()) { + ArrayList<PackageParser.Package> retValue = new ArrayList<>(); + synchronized (mPackages) { + for (SharedLibraryInfo info : deps) { + PackageParser.Package depPackage = mPackages.get(info.getPackageName()); + if (depPackage != null) { + retValue.add(depPackage); + } + } } - return null; + return retValue; + } else { + return Collections.emptyList(); } } diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java index 91ad11e53538..5a473c1819c1 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java +++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java @@ -174,6 +174,18 @@ public final class DexoptUtils { } /** + * Creates the class loader context for the given shared library. + */ + public static String getClassLoaderContext(SharedLibraryInfo info) { + String sharedLibrariesContext = ""; + if (info.getDependencies() != null) { + sharedLibrariesContext = encodeSharedLibraries(info.getDependencies()); + } + return encodeClassLoader( + "", SHARED_LIBRARY_LOADER_TYPE, sharedLibrariesContext); + } + + /** * Recursive method to generate the class loader context dependencies for the split with the * given index. {@param classLoaderContexts} acts as an accumulator. Upton return * {@code classLoaderContexts[index]} will contain the split dependency. diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java index aa51ecdca40b..a91455ada165 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java @@ -332,6 +332,20 @@ public class DexoptUtilsTest { } @Test + public void testSharedLibraryContext() { + SharedLibraryInfo sharedLibrary = + createMockSharedLibrary(new String[] {"a.dex", "b.dex"}).get(0); + String context = DexoptUtils.getClassLoaderContext(sharedLibrary); + assertEquals("PCL[]", context); + + SharedLibraryInfo otherSharedLibrary = + createMockSharedLibrary(new String[] {"c.dex"}).get(0); + otherSharedLibrary.addDependency(sharedLibrary); + context = DexoptUtils.getClassLoaderContext(otherSharedLibrary); + assertEquals("PCL[]{PCL[a.dex:b.dex]}", context); + } + + @Test public void testProcessContextForDexLoad() { List<String> classLoaders = Arrays.asList( DELEGATE_LAST_CLASS_LOADER_NAME, |