diff options
| author | 2015-04-02 23:11:10 +0000 | |
|---|---|---|
| committer | 2015-04-02 23:11:11 +0000 | |
| commit | 3d8b7f4d50c2f7c64ec4e5874fd95cf837ddc12e (patch) | |
| tree | 768876b59d0b621d1123b22f7f0588b4f2204d38 | |
| parent | 3cc9e5d68d89ea1ffa79ad6981585bc46362c4a7 (diff) | |
| parent | b94c1657eb0140f7b91f5372a9f76de5a3d87e36 (diff) | |
Merge "Support for storing OAT files in app directory"
8 files changed, 155 insertions, 72 deletions
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 05c19db1fd48..b3c558b1dda3 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -900,6 +900,20 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** * @hide */ + public boolean isSystemApp() { + return (flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + /** + * @hide + */ + public boolean isUpdatedSystemApp() { + return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; + } + + /** + * @hide + */ @Override protected ApplicationInfo getApplicationInfo() { return this; } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 4952ba1989c8..532092935ae0 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -4444,6 +4444,20 @@ public class PackageParser { return applicationInfo.isForwardLocked(); } + /** + * @hide + */ + public boolean isSystemApp() { + return applicationInfo.isSystemApp(); + } + + /** + * @hide + */ + public boolean isUpdatedSystemApp() { + return applicationInfo.isUpdatedSystemApp(); + } + public String toString() { return "Package{" + Integer.toHexString(System.identityHashCode(this)) diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java index 433a54b4341a..a4cdf194189f 100644 --- a/core/java/com/android/internal/os/InstallerConnection.java +++ b/core/java/com/android/internal/os/InstallerConnection.java @@ -91,11 +91,11 @@ public class InstallerConnection { } public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) { - return dexopt(apkPath, uid, isPublic, "*", instructionSet, false, false); + return dexopt(apkPath, uid, isPublic, "*", instructionSet, false, false, null); } public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, - String instructionSet, boolean vmSafeMode, boolean debuggable) { + String instructionSet, boolean vmSafeMode, boolean debuggable, String outputPath) { StringBuilder builder = new StringBuilder("dexopt"); builder.append(' '); builder.append(apkPath); @@ -108,6 +108,8 @@ public class InstallerConnection { builder.append(instructionSet); builder.append(vmSafeMode ? " 1" : " 0"); builder.append(debuggable ? " 1" : " 0"); + builder.append(' '); + builder.append(outputPath != null ? outputPath : "!"); return execute(builder.toString()); } diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 5cde8ea1db68..b4a44a646551 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageStats; import android.os.Build; @@ -83,14 +84,15 @@ public final class Installer extends SystemService { } public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, - String instructionSet, boolean vmSafeMode, boolean debuggable) { + String instructionSet, boolean vmSafeMode, boolean debuggable, + @Nullable String outputPath) { if (!isValidInstructionSet(instructionSet)) { Slog.e(TAG, "Invalid instruction set: " + instructionSet); return -1; } return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, instructionSet, vmSafeMode, - debuggable); + debuggable, outputPath); } public int idmap(String targetApkPath, String overlayApkPath, int uid) { @@ -134,6 +136,16 @@ public final class Installer extends SystemService { return mInstaller.execute(builder.toString()); } + /** + * Removes packageDir or its subdirectory + */ + public int rmPackageDir(String packageDir) { + StringBuilder builder = new StringBuilder("rmpackagedir"); + builder.append(' '); + builder.append(packageDir); + return mInstaller.execute(builder.toString()); + } + public int remove(String name, int userId) { StringBuilder builder = new StringBuilder("remove"); builder.append(' '); @@ -331,6 +343,15 @@ public final class Installer extends SystemService { return (mInstaller.execute(builder.toString()) == 0); } + public int createOatDir(String oatDir, String dexInstructionSet) { + StringBuilder builder = new StringBuilder("createoatdir"); + builder.append(' '); + builder.append(oatDir); + builder.append(' '); + builder.append(dexInstructionSet); + return mInstaller.execute(builder.toString()); + } + /** * Returns true iff. {@code instructionSet} is a valid instruction set. */ diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java index 79e7a20fff0f..5092ebf9d4b9 100644 --- a/services/core/java/com/android/server/pm/InstructionSets.java +++ b/services/core/java/com/android/server/pm/InstructionSets.java @@ -74,6 +74,7 @@ public class InstructionSets { * a native bridge this might be different than the one shared libraries use. */ public static String getDexCodeInstructionSet(String sharedLibraryIsa) { + // TODO b/19550105 Build mapping once instead of querying each time String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa); return TextUtils.isEmpty(dexCodeIsa) ? sharedLibraryIsa : dexCodeIsa; } @@ -111,4 +112,13 @@ public class InstructionSets { return allInstructionSets; } + + public static String getPrimaryInstructionSet(ApplicationInfo info) { + if (info.primaryCpuAbi == null) { + return getPreferredInstructionSet(); + } + + return VMRuntime.getInstructionSet(info.primaryCpuAbi); + } + } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 2dbce0a4ff52..680ec4b4bb87 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import android.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.content.pm.PackageParser; import android.os.UserHandle; @@ -23,6 +24,7 @@ import android.util.ArraySet; import android.util.Log; import android.util.Slog; +import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; @@ -38,7 +40,9 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; * Helper class for running dexopt command on packages. */ final class PackageDexOptimizer { - static final String TAG = "PackageManager.DexOptimizer"; + private static final String TAG = "PackageManager.DexOptimizer"; + static final String OAT_DIR_NAME = "oat"; + // TODO b/19550105 Remove error codes and use exceptions static final int DEX_OPT_SKIPPED = 0; static final int DEX_OPT_PERFORMED = 1; static final int DEX_OPT_DEFERRED = 2; @@ -117,19 +121,30 @@ final class PackageDexOptimizer { final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path, pkg.packageName, dexCodeInstructionSet, defer); if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) { + File oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet); Log.i(TAG, "Running dexopt on: " + path + " pkg=" + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet - + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable); + + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable + + " oatDir = " + oatDir); final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); - final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid, - !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet, - vmSafeMode, debuggable); - if (ret < 0) { - // Don't bother running dexopt again if we failed, it will probably - // just result in an error again. Also, don't bother dexopting for other - // paths & ISAs. - return DEX_OPT_FAILED; + if (oatDir != null) { + int ret = mPackageManagerService.mInstaller.dexopt( + path, sharedGid, !pkg.isForwardLocked(), pkg.packageName, + dexCodeInstructionSet, vmSafeMode, debuggable, + oatDir.getAbsolutePath()); + if (ret < 0) { + return DEX_OPT_FAILED; + } + } else { + final int ret = mPackageManagerService.mInstaller + .dexopt(path, sharedGid, + !pkg.isForwardLocked(), pkg.packageName, + dexCodeInstructionSet, + vmSafeMode, debuggable, null); + if (ret < 0) { + return DEX_OPT_FAILED; + } } performedDexOpt = true; @@ -186,6 +201,36 @@ final class PackageDexOptimizer { return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED; } + /** + * Creates oat dir for the specified package. In certain cases oat directory + * <strong>cannot</strong> be created: + * <ul> + * <li>{@code pkg} is a system app, which is not updated.</li> + * <li>Package location is not a directory, i.e. monolithic install.</li> + * </ul> + * + * @return oat directory or null, if oat directory cannot be created. + */ + @Nullable + private File createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet) + throws IOException { + if (pkg.isSystemApp() && !pkg.isUpdatedSystemApp()) { + return null; + } + File codePath = new File(pkg.codePath); + if (codePath.isDirectory()) { + File oatDir = getOatDir(codePath); + mPackageManagerService.mInstaller.createOatDir(oatDir.getAbsolutePath(), + dexInstructionSet); + return oatDir; + } + return null; + } + + static File getOatDir(File codePath) { + return new File(codePath, OAT_DIR_NAME); + } + private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets, boolean forceDex, boolean defer, ArraySet<String> done) { for (String libName : libs) { @@ -209,7 +254,7 @@ final class PackageDexOptimizer { public void addPackageForDeferredDexopt(PackageParser.Package pkg) { if (mDeferredDexOpt == null) { - mDeferredDexOpt = new ArraySet<PackageParser.Package>(); + mDeferredDexOpt = new ArraySet<>(); } mDeferredDexOpt.add(pkg); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 2150e9ab002a..95d7a52893d4 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -53,7 +53,6 @@ import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Environment; -import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -225,9 +224,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub { for (File stage : unclaimedStages) { Slog.w(TAG, "Deleting orphan stage " + stage); if (stage.isDirectory()) { - FileUtils.deleteContents(stage); + mPm.mInstaller.rmPackageDir(stage.getAbsolutePath()); + } else { + stage.delete(); } - stage.delete(); } // Clean up orphaned icons diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index aba930fb7abd..67d3cbea2d3e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -59,6 +59,7 @@ import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; +import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet; import android.util.ArrayMap; @@ -1872,9 +1873,10 @@ public class PackageManagerService extends IPackageManager.Stub { removeDataDirsLI(ps.name); if (ps.codePath != null) { if (ps.codePath.isDirectory()) { - FileUtils.deleteContents(ps.codePath); + mInstaller.rmPackageDir(ps.codePath.getAbsolutePath()); + } else { + ps.codePath.delete(); } - ps.codePath.delete(); } if (ps.resourcePath != null && !ps.resourcePath.equals(ps.codePath)) { if (ps.resourcePath.isDirectory()) { @@ -4190,9 +4192,10 @@ public class PackageManagerService extends IPackageManager.Stub { e.error == PackageManager.INSTALL_FAILED_INVALID_APK) { logCriticalInfo(Log.WARN, "Deleting invalid package at " + file); if (file.isDirectory()) { - FileUtils.deleteContents(file); + mInstaller.rmPackageDir(file.getAbsolutePath()); + } else { + file.delete(); } - file.delete(); } } } @@ -4640,7 +4643,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Give priority to system apps. for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) { PackageParser.Package pkg = it.next(); - if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) { + if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) { if (DEBUG_DEXOPT) { Log.i(TAG, "Adding system app " + sortedPkgs.size() + ": " + pkg.packageName); } @@ -4651,7 +4654,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Give priority to updated system apps. for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) { PackageParser.Package pkg = it.next(); - if (isUpdatedSystemApp(pkg)) { + if (pkg.isUpdatedSystemApp()) { if (DEBUG_DEXOPT) { Log.i(TAG, "Adding updated system app " + sortedPkgs.size() + ": " + pkg.packageName); } @@ -4772,14 +4775,6 @@ public class PackageManagerService extends IPackageManager.Stub { return performDexOpt(packageName, instructionSet, false); } - private static String getPrimaryInstructionSet(ApplicationInfo info) { - if (info.primaryCpuAbi == null) { - return getPreferredInstructionSet(); - } - - return VMRuntime.getInstructionSet(info.primaryCpuAbi); - } - public boolean performDexOpt(String packageName, String instructionSet, boolean backgroundDexopt) { boolean dexopt = mLazyDexOpt || backgroundDexopt; boolean updateUsage = !backgroundDexopt; // Don't update usage if this is just a backgroundDexopt @@ -5513,7 +5508,7 @@ public class PackageManagerService extends IPackageManager.Stub { final String path = scanFile.getPath(); final String codePath = pkg.applicationInfo.getCodePath(); final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting); - if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) { + if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) { setBundledAppAbisAndRoots(pkg, pkgSetting); // If we haven't found any native libraries for the app, check if it has @@ -5728,7 +5723,6 @@ public class PackageManagerService extends IPackageManager.Stub { throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI"); } } - if (mFactoryTest && pkg.requestedPermissions.contains( android.Manifest.permission.FACTORY_TEST)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST; @@ -5744,7 +5738,7 @@ public class PackageManagerService extends IPackageManager.Stub { for (int i=0; i<pkg.libraryNames.size(); i++) { String name = pkg.libraryNames.get(i); boolean allowed = false; - if (isUpdatedSystemApp(pkg)) { + 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- @@ -6350,7 +6344,7 @@ public class PackageManagerService extends IPackageManager.Stub { final ApplicationInfo info = pkg.applicationInfo; final String codePath = pkg.codePath; final File codeFile = new File(codePath); - final boolean bundledApp = isSystemApp(info) && !isUpdatedSystemApp(info); + final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp(); final boolean asecApp = info.isForwardLocked() || isExternal(info); info.nativeLibraryRootDir = null; @@ -7002,7 +6996,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (isSystemApp(pkg)) { // For updated system applications, a system permission // is granted only if it had been defined by the original application. - if (isUpdatedSystemApp(pkg)) { + if (pkg.isUpdatedSystemApp()) { final PackageSetting sysPs = mSettings .getDisabledSystemPkgLPr(pkg.packageName); final GrantedPermissions origGp = sysPs.sharedUser != null @@ -7090,7 +7084,7 @@ public class PackageManagerService extends IPackageManager.Stub { } public final void addActivity(PackageParser.Activity a, String type) { - final boolean systemApp = isSystemApp(a.info.applicationInfo); + final boolean systemApp = a.info.applicationInfo.isSystemApp(); mActivities.put(a.getComponentName(), a); if (DEBUG_SHOW_INFO) Log.v( @@ -7217,7 +7211,7 @@ public class PackageManagerService extends IPackageManager.Stub { } else { res.icon = info.icon; } - res.system = isSystemApp(res.activityInfo.applicationInfo); + res.system = res.activityInfo.applicationInfo.isSystemApp(); return res; } @@ -7433,7 +7427,7 @@ public class PackageManagerService extends IPackageManager.Stub { res.labelRes = info.labelRes; res.nonLocalizedLabel = info.nonLocalizedLabel; res.icon = info.icon; - res.system = isSystemApp(res.serviceInfo.applicationInfo); + res.system = res.serviceInfo.applicationInfo.isSystemApp(); return res; } @@ -7656,7 +7650,7 @@ public class PackageManagerService extends IPackageManager.Stub { res.labelRes = info.labelRes; res.nonLocalizedLabel = info.nonLocalizedLabel; res.icon = info.icon; - res.system = isSystemApp(res.providerInfo.applicationInfo); + res.system = res.providerInfo.applicationInfo.isSystemApp(); return res; } @@ -9386,9 +9380,10 @@ public class PackageManagerService extends IPackageManager.Stub { } if (codeFile.isDirectory()) { - FileUtils.deleteContents(codeFile); + mInstaller.rmPackageDir(codeFile.getAbsolutePath()); + } else { + codeFile.delete(); } - codeFile.delete(); if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) { resourceFile.delete(); @@ -9830,22 +9825,6 @@ public class PackageManagerService extends IPackageManager.Stub { return result; } - // Utility method used to ignore ADD/REMOVE events - // by directory observer. - private static boolean ignoreCodePath(String fullPathStr) { - String apkName = deriveCodePathName(fullPathStr); - int idx = apkName.lastIndexOf(INSTALL_PACKAGE_SUFFIX); - if (idx != -1 && ((idx+1) < apkName.length())) { - // Make sure the package ends with a numeral - String version = apkName.substring(idx+1); - try { - Integer.parseInt(version); - return true; - } catch (NumberFormatException e) {} - } - return false; - } - // Utility method that returns the relative package path with respect // to the installation directory. Like say for /data/data/com.test-1.apk // string com.test-1 is returned. @@ -10454,13 +10433,23 @@ public class PackageManagerService extends IPackageManager.Stub { return; } + // Run dexopt before old package gets removed, to minimize time when app is not available + int result = mPackageDexOptimizer + .performDexOpt(pkg, null /* instruction sets */, true /* forceDex */, + false /* defer */, false /* inclDependencies */); + if (result == PackageDexOptimizer.DEX_OPT_FAILED) { + res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath); + return; + } + if (!args.doRename(res.returnCode, pkg, oldCodePath)) { res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); return; } if (replace) { - replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user, + // Call replacePackageLI with SCAN_NO_DEX, since we already made dexopt + replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING | SCAN_NO_DEX, args.user, installerPackageName, res); } else { installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES, @@ -10502,10 +10491,6 @@ public class PackageManagerService extends IPackageManager.Stub { return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; } - private static boolean isSystemApp(ApplicationInfo info) { - return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; - } - private static boolean isSystemApp(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0; } @@ -10514,14 +10499,6 @@ public class PackageManagerService extends IPackageManager.Stub { return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } - private static boolean isUpdatedSystemApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; - } - - private static boolean isUpdatedSystemApp(ApplicationInfo info) { - return (info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; - } - private int packageFlagsToInstallFlags(PackageSetting ps) { int installFlags = 0; if (isExternal(ps)) { |