diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 05c19db1fd483..b3c558b1dda31 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -897,6 +897,20 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { return (privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0; } + /** + * @hide + */ + public boolean isSystemApp() { + return (flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + /** + * @hide + */ + public boolean isUpdatedSystemApp() { + return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; + } + /** * @hide */ diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 4952ba1989c84..532092935ae0f 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 433a54b4341a5..a4cdf194189f3 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 5cde8ea1db683..b4a44a6465515 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 79e7a20fff0f3..5092ebf9d4b93 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 2dbce0a4ff524..680ec4b4bb870 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 + * cannot be created: + *