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: + * + * + * @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 libs, String[] instructionSets, boolean forceDex, boolean defer, ArraySet done) { for (String libName : libs) { @@ -209,7 +254,7 @@ final class PackageDexOptimizer { public void addPackageForDeferredDexopt(PackageParser.Package pkg) { if (mDeferredDexOpt == null) { - mDeferredDexOpt = new ArraySet(); + 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 2150e9ab002ab..95d7a52893d41 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 aba930fb7abd5..67d3cbea2d3ef 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 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 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