Merge "Extracted a separate class to run dexopt on packages"
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index e822708..e1a2aa9 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -881,6 +881,13 @@
/**
* @hide
*/
+ public boolean isForwardLocked() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 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 77dc27a..4d9445d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4431,6 +4431,13 @@
return false;
}
+ /**
+ * @hide
+ */
+ public boolean isForwardLocked() {
+ return applicationInfo.isForwardLocked();
+ }
+
public String toString() {
return "Package{"
+ Integer.toHexString(System.identityHashCode(this))
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
new file mode 100644
index 0000000..79e7a20
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import dalvik.system.VMRuntime;
+
+/**
+ * Provides various methods for obtaining and converting of instruction sets.
+ *
+ * @hide
+ */
+public class InstructionSets {
+ private static final String PREFERRED_INSTRUCTION_SET =
+ VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);;
+ public static String[] getAppDexInstructionSets(ApplicationInfo info) {
+ if (info.primaryCpuAbi != null) {
+ if (info.secondaryCpuAbi != null) {
+ return new String[] {
+ VMRuntime.getInstructionSet(info.primaryCpuAbi),
+ VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
+ } else {
+ return new String[] {
+ VMRuntime.getInstructionSet(info.primaryCpuAbi) };
+ }
+ }
+
+ return new String[] { getPreferredInstructionSet() };
+ }
+
+ public static String[] getAppDexInstructionSets(PackageSetting ps) {
+ if (ps.primaryCpuAbiString != null) {
+ if (ps.secondaryCpuAbiString != null) {
+ return new String[] {
+ VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
+ VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
+ } else {
+ return new String[] {
+ VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
+ }
+ }
+
+ return new String[] { getPreferredInstructionSet() };
+ }
+
+ public static String getPreferredInstructionSet() {
+ return PREFERRED_INSTRUCTION_SET;
+ }
+
+ /**
+ * Returns the instruction set that should be used to compile dex code. In the presence of
+ * a native bridge this might be different than the one shared libraries use.
+ */
+ public static String getDexCodeInstructionSet(String sharedLibraryIsa) {
+ String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
+ return TextUtils.isEmpty(dexCodeIsa) ? sharedLibraryIsa : dexCodeIsa;
+ }
+
+ public static String[] getDexCodeInstructionSets(String[] instructionSets) {
+ ArraySet<String> dexCodeInstructionSets = new ArraySet<String>(instructionSets.length);
+ for (String instructionSet : instructionSets) {
+ dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
+ }
+ return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
+ }
+
+ /**
+ * Returns deduplicated list of supported instructions for dex code.
+ */
+ public static String[] getAllDexCodeInstructionSets() {
+ String[] supportedInstructionSets = new String[Build.SUPPORTED_ABIS.length];
+ for (int i = 0; i < supportedInstructionSets.length; i++) {
+ String abi = Build.SUPPORTED_ABIS[i];
+ supportedInstructionSets[i] = VMRuntime.getInstructionSet(abi);
+ }
+ return getDexCodeInstructionSets(supportedInstructionSets);
+ }
+
+ public static List<String> getAllInstructionSets() {
+ final String[] allAbis = Build.SUPPORTED_ABIS;
+ final List<String> allInstructionSets = new ArrayList<String>(allAbis.length);
+
+ for (String abi : allAbis) {
+ final String instructionSet = VMRuntime.getInstructionSet(abi);
+ if (!allInstructionSets.contains(instructionSet)) {
+ allInstructionSets.add(instructionSet);
+ }
+ }
+
+ return allInstructionSets;
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
new file mode 100644
index 0000000..2dbce0a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageParser;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import dalvik.system.DexFile;
+import dalvik.system.StaleDexCacheError;
+
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+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";
+ static final int DEX_OPT_SKIPPED = 0;
+ static final int DEX_OPT_PERFORMED = 1;
+ static final int DEX_OPT_DEFERRED = 2;
+ static final int DEX_OPT_FAILED = -1;
+
+ private final PackageManagerService mPackageManagerService;
+ private ArraySet<PackageParser.Package> mDeferredDexOpt;
+
+ PackageDexOptimizer(PackageManagerService packageManagerService) {
+ this.mPackageManagerService = packageManagerService;
+ }
+
+ /**
+ * Performs dexopt on all code paths and libraries of the specified package for specified
+ * instruction sets.
+ *
+ * <p>Calls to {@link com.android.server.pm.Installer#dexopt} are synchronized on
+ * {@link PackageManagerService#mInstallLock}.
+ */
+ int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
+ boolean forceDex, boolean defer, boolean inclDependencies) {
+ ArraySet<String> done;
+ if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
+ done = new ArraySet<String>();
+ done.add(pkg.packageName);
+ } else {
+ done = null;
+ }
+ synchronized (mPackageManagerService.mInstallLock) {
+ return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
+ }
+ }
+
+ private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
+ boolean forceDex, boolean defer, ArraySet<String> done) {
+ final String[] instructionSets = targetInstructionSets != null ?
+ targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
+
+ if (done != null) {
+ done.add(pkg.packageName);
+ if (pkg.usesLibraries != null) {
+ performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
+ }
+ if (pkg.usesOptionalLibraries != null) {
+ performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer,
+ done);
+ }
+ }
+
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+ return DEX_OPT_SKIPPED;
+ }
+
+ final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
+ final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+
+ final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+ boolean performedDexOpt = false;
+ // There are three basic cases here:
+ // 1.) we need to dexopt, either because we are forced or it is needed
+ // 2.) we are deferring a needed dexopt
+ // 3.) we are skipping an unneeded dexopt
+ final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
+ continue;
+ }
+
+ for (String path : paths) {
+ try {
+ // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
+ // package or the one we find does not match the image checksum (i.e. it was
+ // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
+ // odex file and it matches the checksum of the image but not its base address,
+ // meaning we need to move it.
+ final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
+ pkg.packageName, dexCodeInstructionSet, defer);
+ if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
+ Log.i(TAG, "Running dexopt on: " + path + " pkg="
+ + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+ + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable);
+ 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;
+ }
+
+ performedDexOpt = true;
+ } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
+ Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ final int ret = mPackageManagerService.mInstaller.patchoat(path, sharedGid,
+ !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet);
+
+ if (ret < 0) {
+ // Don't bother running patchoat 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;
+ }
+
+ performedDexOpt = true;
+ }
+
+ // We're deciding to defer a needed dexopt. Don't bother dexopting for other
+ // paths and instruction sets. We'll deal with them all together when we process
+ // our list of deferred dexopts.
+ if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
+ addPackageForDeferredDexopt(pkg);
+ return DEX_OPT_DEFERRED;
+ }
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Apk not found for dexopt: " + path);
+ return DEX_OPT_FAILED;
+ } catch (IOException e) {
+ Slog.w(TAG, "IOException reading apk: " + path, e);
+ return DEX_OPT_FAILED;
+ } catch (StaleDexCacheError e) {
+ Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
+ return DEX_OPT_FAILED;
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception when doing dexopt : ", e);
+ return DEX_OPT_FAILED;
+ }
+ }
+
+ // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
+ // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
+ // it isn't required. We therefore mark that this package doesn't need dexopt unless
+ // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
+ // it.
+ pkg.mDexOptPerformed.add(dexCodeInstructionSet);
+ }
+
+ // If we've gotten here, we're sure that no error occurred and that we haven't
+ // deferred dex-opt. We've either dex-opted one more paths or instruction sets or
+ // we've skipped all of them because they are up to date. In both cases this
+ // package doesn't need dexopt any longer.
+ return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+ }
+
+ private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
+ boolean forceDex, boolean defer, ArraySet<String> done) {
+ for (String libName : libs) {
+ PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
+ libName);
+ if (libPkg != null && !done.contains(libName)) {
+ performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
+ }
+ }
+ }
+
+ /**
+ * Clears set of deferred dexopt packages.
+ * @return content of dexopt set if it was not empty
+ */
+ public ArraySet<PackageParser.Package> clearDeferredDexOptPackages() {
+ ArraySet<PackageParser.Package> result = mDeferredDexOpt;
+ mDeferredDexOpt = null;
+ return result;
+ }
+
+ public void addPackageForDeferredDexopt(PackageParser.Package pkg) {
+ if (mDeferredDexOpt == null) {
+ mDeferredDexOpt = new ArraySet<PackageParser.Package>();
+ }
+ mDeferredDexOpt.add(pkg);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b297887..aba930f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -55,6 +55,10 @@
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.removeInt;
+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 android.util.ArrayMap;
@@ -184,7 +188,6 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
@@ -213,7 +216,6 @@
import java.util.concurrent.atomic.AtomicLong;
import dalvik.system.DexFile;
-import dalvik.system.StaleDexCacheError;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
@@ -323,13 +325,8 @@
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
- private static String sPreferredInstructionSet;
-
final ServiceThread mHandlerThread;
- private static final String IDMAP_PREFIX = "/data/resource-cache/";
- private static final String IDMAP_SUFFIX = "@idmap";
-
final PackageHandler mHandler;
/**
@@ -466,8 +463,7 @@
final PackageInstallerService mInstallerService;
- ArraySet<PackageParser.Package> mDeferredDexOpt = null;
-
+ private final PackageDexOptimizer mPackageDexOptimizer;
// Cache of users who need badging.
SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
@@ -1050,7 +1046,7 @@
res.pkg.applicationInfo.packageName, null, updateUsers);
// treat asec-hosted packages like removable media on upgrade
- if (isForwardLocked(res.pkg) || isExternal(res.pkg)) {
+ if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.pkg
+ " is ASEC-hosted -> AVAILABLE");
@@ -1338,6 +1334,7 @@
}
mInstaller = installer;
+ mPackageDexOptimizer = new PackageDexOptimizer(this);
getDefaultDisplayMetrics(context, mMetrics);
@@ -1438,9 +1435,10 @@
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
- final List<String> allInstructionSets = getAllInstructionSets();
+ final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
final String[] dexCodeInstructionSets =
- getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));
+ getDexCodeInstructionSets(
+ allInstructionSets.toArray(new String[allInstructionSets.size()]));
/**
* Ensure all external libraries have had dexopt run on them.
@@ -2335,6 +2333,19 @@
return null;
}
+ /**
+ * @hide
+ */
+ PackageParser.Package findSharedNonSystemLibrary(String libName) {
+ synchronized (mPackages) {
+ PackageManagerService.SharedLibraryEntry lib = mSharedLibraries.get(libName);
+ if (lib != null && lib.apk != null) {
+ return mPackages.get(lib.apk);
+ }
+ }
+ return null;
+ }
+
@Override
public FeatureInfo[] getSystemAvailableFeatures() {
Collection<FeatureInfo> featSet;
@@ -4595,8 +4606,7 @@
final ArraySet<PackageParser.Package> pkgs;
synchronized (mPackages) {
- pkgs = mDeferredDexOpt;
- mDeferredDexOpt = null;
+ pkgs = mPackageDexOptimizer.clearDeferredDexOptPackages();
}
if (pkgs != null) {
@@ -4752,8 +4762,8 @@
}
PackageParser.Package p = pkg;
synchronized (mInstallLock) {
- performDexOptLI(p, null /* instruction sets */, false /* force dex */,
- false /* defer */, true /* include dependencies */);
+ mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */,
+ false /* force dex */, false /* defer */, true /* include dependencies */);
}
}
@@ -4802,8 +4812,9 @@
synchronized (mInstallLock) {
final String[] instructionSets = new String[] { targetInstructionSet };
- return performDexOptLI(p, instructionSets, false /* force dex */, false /* defer */,
- true /* include dependencies */) == DEX_OPT_PERFORMED;
+ int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
+ false /* forceDex */, false /* defer */, true /* inclDependencies */);
+ return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
}
}
@@ -4830,227 +4841,6 @@
mPackageUsage.write(true);
}
- private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
- boolean forceDex, boolean defer, ArraySet<String> done) {
- for (int i=0; i<libs.size(); i++) {
- PackageParser.Package libPkg;
- String libName;
- synchronized (mPackages) {
- libName = libs.get(i);
- SharedLibraryEntry lib = mSharedLibraries.get(libName);
- if (lib != null && lib.apk != null) {
- libPkg = mPackages.get(lib.apk);
- } else {
- libPkg = null;
- }
- }
- if (libPkg != null && !done.contains(libName)) {
- performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
- }
- }
- }
-
- static final int DEX_OPT_SKIPPED = 0;
- static final int DEX_OPT_PERFORMED = 1;
- static final int DEX_OPT_DEFERRED = 2;
- static final int DEX_OPT_FAILED = -1;
-
- private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
- boolean forceDex, boolean defer, ArraySet<String> done) {
- final String[] instructionSets = targetInstructionSets != null ?
- targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
-
- if (done != null) {
- done.add(pkg.packageName);
- if (pkg.usesLibraries != null) {
- performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
- }
- if (pkg.usesOptionalLibraries != null) {
- performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer, done);
- }
- }
-
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
- return DEX_OPT_SKIPPED;
- }
-
- final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
- final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-
- final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
- boolean performedDexOpt = false;
- // There are three basic cases here:
- // 1.) we need to dexopt, either because we are forced or it is needed
- // 2.) we are defering a needed dexopt
- // 3.) we are skipping an unneeded dexopt
- final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
- for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
- continue;
- }
-
- for (String path : paths) {
- try {
- // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
- // patckage or the one we find does not match the image checksum (i.e. it was
- // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
- // odex file and it matches the checksum of the image but not its base address,
- // meaning we need to move it.
- final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
- pkg.packageName, dexCodeInstructionSet, defer);
- if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
- Log.i(TAG, "Running dexopt on: " + path + " pkg="
- + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
- + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable);
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- final int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
- 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;
- }
-
- performedDexOpt = true;
- } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
- Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- final int ret = mInstaller.patchoat(path, sharedGid, !isForwardLocked(pkg),
- pkg.packageName, dexCodeInstructionSet);
-
- if (ret < 0) {
- // Don't bother running patchoat 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;
- }
-
- performedDexOpt = true;
- }
-
- // We're deciding to defer a needed dexopt. Don't bother dexopting for other
- // paths and instruction sets. We'll deal with them all together when we process
- // our list of deferred dexopts.
- if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
- if (mDeferredDexOpt == null) {
- mDeferredDexOpt = new ArraySet<PackageParser.Package>();
- }
- mDeferredDexOpt.add(pkg);
- return DEX_OPT_DEFERRED;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Apk not found for dexopt: " + path);
- return DEX_OPT_FAILED;
- } catch (IOException e) {
- Slog.w(TAG, "IOException reading apk: " + path, e);
- return DEX_OPT_FAILED;
- } catch (StaleDexCacheError e) {
- Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
- return DEX_OPT_FAILED;
- } catch (Exception e) {
- Slog.w(TAG, "Exception when doing dexopt : ", e);
- return DEX_OPT_FAILED;
- }
- }
-
- // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
- // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
- // it isn't required. We therefore mark that this package doesn't need dexopt unless
- // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
- // it.
- pkg.mDexOptPerformed.add(dexCodeInstructionSet);
- }
-
- // If we've gotten here, we're sure that no error occurred and that we haven't
- // deferred dex-opt. We've either dex-opted one more paths or instruction sets or
- // we've skipped all of them because they are up to date. In both cases this
- // package doesn't need dexopt any longer.
- return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
- }
-
- private static String[] getAppDexInstructionSets(ApplicationInfo info) {
- if (info.primaryCpuAbi != null) {
- if (info.secondaryCpuAbi != null) {
- return new String[] {
- VMRuntime.getInstructionSet(info.primaryCpuAbi),
- VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
- } else {
- return new String[] {
- VMRuntime.getInstructionSet(info.primaryCpuAbi) };
- }
- }
-
- return new String[] { getPreferredInstructionSet() };
- }
-
- private static String[] getAppDexInstructionSets(PackageSetting ps) {
- if (ps.primaryCpuAbiString != null) {
- if (ps.secondaryCpuAbiString != null) {
- return new String[] {
- VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
- VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
- } else {
- return new String[] {
- VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
- }
- }
-
- return new String[] { getPreferredInstructionSet() };
- }
-
- private static String getPreferredInstructionSet() {
- if (sPreferredInstructionSet == null) {
- sPreferredInstructionSet = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
- }
-
- return sPreferredInstructionSet;
- }
-
- private static List<String> getAllInstructionSets() {
- final String[] allAbis = Build.SUPPORTED_ABIS;
- final List<String> allInstructionSets = new ArrayList<String>(allAbis.length);
-
- for (String abi : allAbis) {
- final String instructionSet = VMRuntime.getInstructionSet(abi);
- if (!allInstructionSets.contains(instructionSet)) {
- allInstructionSets.add(instructionSet);
- }
- }
-
- return allInstructionSets;
- }
-
- /**
- * Returns the instruction set that should be used to compile dex code. In the presence of
- * a native bridge this might be different than the one shared libraries use.
- */
- private static String getDexCodeInstructionSet(String sharedLibraryIsa) {
- String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
- return (dexCodeIsa.isEmpty() ? sharedLibraryIsa : dexCodeIsa);
- }
-
- private static String[] getDexCodeInstructionSets(String[] instructionSets) {
- ArraySet<String> dexCodeInstructionSets = new ArraySet<String>(instructionSets.length);
- for (String instructionSet : instructionSets) {
- dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
- }
- return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
- }
-
- /**
- * Returns deduplicated list of supported instructions for dex code.
- */
- public static String[] getAllDexCodeInstructionSets() {
- String[] supportedInstructionSets = new String[Build.SUPPORTED_ABIS.length];
- for (int i = 0; i < supportedInstructionSets.length; i++) {
- String abi = Build.SUPPORTED_ABIS[i];
- supportedInstructionSets[i] = VMRuntime.getInstructionSet(abi);
- }
- return getDexCodeInstructionSets(supportedInstructionSets);
- }
-
@Override
public void forceDexOpt(String packageName) {
enforceSystemOrRoot("forceDexOpt");
@@ -5066,25 +4856,14 @@
synchronized (mInstallLock) {
final String[] instructionSets = new String[] {
getPrimaryInstructionSet(pkg.applicationInfo) };
- final int res = performDexOptLI(pkg, instructionSets, true, false, true);
- if (res != DEX_OPT_PERFORMED) {
+ final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
+ true /*forceDex*/, false /* defer */, true /* inclDependencies */);
+ if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
throw new IllegalStateException("Failed to dexopt: " + res);
}
}
}
- private int performDexOptLI(PackageParser.Package pkg, String[] instructionSets,
- boolean forceDex, boolean defer, boolean inclDependencies) {
- ArraySet<String> done;
- if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
- done = new ArraySet<String>();
- done.add(pkg.packageName);
- } else {
- done = null;
- }
- return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
- }
-
private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
Slog.w(TAG, "Unable to update from " + oldPkg.name
@@ -5100,10 +4879,6 @@
return true;
}
- File getDataPathForUser(int userId) {
- return new File(mUserAppDataDir.getAbsolutePath() + File.separator + userId);
- }
-
private File getDataPathForPackage(String packageName, int userId) {
/*
* Until we fully support multiple users, return the directory we
@@ -5771,7 +5546,7 @@
// pass once we've determined ABI below.
setNativeLibraryPaths(pkg);
- final boolean isAsec = isForwardLocked(pkg) || isExternal(pkg);
+ final boolean isAsec = pkg.isForwardLocked() || isExternal(pkg);
final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
@@ -5947,8 +5722,9 @@
}
if ((scanFlags & SCAN_NO_DEX) == 0) {
- if (performDexOptLI(pkg, null /* instruction sets */, forceDex,
- (scanFlags & SCAN_DEFER_DEX) != 0, false) == DEX_OPT_FAILED) {
+ int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
+ forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */);
+ if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI");
}
}
@@ -6022,8 +5798,10 @@
if ((scanFlags & SCAN_NO_DEX) == 0) {
for (int i = 0; i < clientLibPkgs.size(); i++) {
PackageParser.Package clientPkg = clientLibPkgs.get(i);
- if (performDexOptLI(clientPkg, null /* instruction sets */, forceDex,
- (scanFlags & SCAN_DEFER_DEX) != 0, false) == DEX_OPT_FAILED) {
+ int result = mPackageDexOptimizer.performDexOpt(clientPkg,
+ null /* instruction sets */, forceDex,
+ (scanFlags & SCAN_DEFER_DEX) != 0, false);
+ if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
"scanPackageLI failed to dexopt clientLibPkgs");
}
@@ -6492,14 +6270,15 @@
ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
- if (performDexOptLI(ps.pkg, null /* instruction sets */, forceDexOpt,
- deferDexOpt, true) == DEX_OPT_FAILED) {
+ int result = mPackageDexOptimizer.performDexOpt(ps.pkg,
+ null /* instruction sets */, forceDexOpt, deferDexOpt, true);
+ if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
ps.primaryCpuAbiString = null;
ps.pkg.applicationInfo.primaryCpuAbi = null;
return;
} else {
mInstaller.rmdex(ps.codePathString,
- getDexCodeInstructionSet(getPreferredInstructionSet()));
+ getDexCodeInstructionSet(getPreferredInstructionSet()));
}
}
}
@@ -6572,7 +6351,7 @@
final String codePath = pkg.codePath;
final File codeFile = new File(codePath);
final boolean bundledApp = isSystemApp(info) && !isUpdatedSystemApp(info);
- final boolean asecApp = isForwardLocked(info) || isExternal(info);
+ final boolean asecApp = info.isForwardLocked() || isExternal(info);
info.nativeLibraryRootDir = null;
info.nativeLibraryRootRequiresIsa = false;
@@ -9407,6 +9186,25 @@
}
}
+ private void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
+ if (!allCodePaths.isEmpty()) {
+ if (instructionSets == null) {
+ throw new IllegalStateException("instructionSet == null");
+ }
+ String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+ for (String codePath : allCodePaths) {
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove dex file for package: "
+ + " at location " + codePath + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
+ }
+ }
+ }
+ }
+ }
+
/**
* Logic to handle installation of non-ASEC applications, including copying
* and renaming logic.
@@ -9619,23 +9417,7 @@
}
cleanUp();
-
- if (!allCodePaths.isEmpty()) {
- if (instructionSets == null) {
- throw new IllegalStateException("instructionSet == null");
- }
- String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
- for (String codePath : allCodePaths) {
- for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location " + codePath + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- }
- }
- }
- }
+ removeDexFiles(allCodePaths, instructionSets);
}
boolean doPostDeleteLI(boolean delete) {
@@ -9940,31 +9722,10 @@
private void cleanUpResourcesLI(List<String> allCodePaths) {
cleanUp();
-
- if (!allCodePaths.isEmpty()) {
- if (instructionSets == null) {
- throw new IllegalStateException("instructionSet == null");
- }
- String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
- for (String codePath : allCodePaths) {
- for (String dexCodeInstructionSet : dexCodeInstructionSets) {
- int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location " + codePath + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- }
- }
- }
- }
+ removeDexFiles(allCodePaths, instructionSets);
}
- boolean matchContainer(String app) {
- if (cid.startsWith(app)) {
- return true;
- }
- return false;
- }
+
String getPackageName() {
return getAsecPackageName(cid);
@@ -10282,7 +10043,7 @@
// If deleted package lived in a container, give users a chance to
// relinquish resources before killing.
- if (isForwardLocked(deletedPackage) || isExternal(deletedPackage)) {
+ if (deletedPackage.isForwardLocked() || isExternal(deletedPackage)) {
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + deletedPackage + " is ASEC-hosted -> UNAVAILABLE");
}
@@ -10323,7 +10084,7 @@
// Parse old package
boolean oldOnSd = isExternal(deletedPackage);
int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY |
- (isForwardLocked(deletedPackage) ? PackageParser.PARSE_FORWARD_LOCK : 0) |
+ (deletedPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) |
(oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0);
int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
try {
@@ -10713,18 +10474,6 @@
}
}
- private static boolean isForwardLocked(PackageParser.Package pkg) {
- return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
- }
-
- private static boolean isForwardLocked(ApplicationInfo info) {
- return (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
- }
-
- private boolean isForwardLocked(PackageSetting ps) {
- return (ps.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
- }
-
private static boolean isMultiArch(PackageSetting ps) {
return (ps.pkgFlags & ApplicationInfo.FLAG_MULTIARCH) != 0;
}
@@ -10778,7 +10527,7 @@
if (isExternal(ps)) {
installFlags |= PackageManager.INSTALL_EXTERNAL;
}
- if (isForwardLocked(ps)) {
+ if (ps.isForwardLocked()) {
installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
}
return installFlags;
@@ -11632,7 +11381,7 @@
if (ps != null) {
libDirRoot = ps.legacyNativeLibraryPathString;
}
- if (p != null && (isExternal(p) || isForwardLocked(p))) {
+ if (p != null && (isExternal(p) || p.isForwardLocked())) {
String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
if (secureContainerId != null) {
asecPath = PackageHelper.getSdFilesystem(secureContainerId);
@@ -11646,7 +11395,7 @@
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- if (isForwardLocked(p)) {
+ if (p.isForwardLocked()) {
publicSrcDir = applicationInfo.getBaseResourcePath();
}
}
@@ -12986,7 +12735,7 @@
}
final AsecInstallArgs args = new AsecInstallArgs(cid,
- getAppDexInstructionSets(ps), isForwardLocked(ps));
+ getAppDexInstructionSets(ps), ps.isForwardLocked());
// The package status is changed only if the code path
// matches between settings and the container id.
if (ps.codePathString != null
@@ -13268,7 +13017,7 @@
Slog.w(TAG, "No move required. Trying to move to same location");
returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
} else {
- if (isForwardLocked(pkg)) {
+ if (pkg.isForwardLocked()) {
currInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
newInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 8ea0bee..06d842a 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -64,4 +64,8 @@
public boolean isPrivileged() {
return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
+
+ public boolean isForwardLocked() {
+ return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
+ }
}
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 111c09b..de9360e 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -18,6 +18,7 @@
import com.android.server.EventLogTags;
import com.android.server.SystemService;
+import com.android.server.pm.InstructionSets;
import com.android.server.pm.PackageManagerService;
import android.app.Notification;
@@ -341,7 +342,7 @@
}
private static boolean isBootImageOnDisk() {
- for (String instructionSet : PackageManagerService.getAllDexCodeInstructionSets()) {
+ for (String instructionSet : InstructionSets.getAllDexCodeInstructionSets()) {
if (!VMRuntime.isBootClassPathOnDisk(instructionSet)) {
return false;
}