Compile secondary dex files in DexManager
am: 7218363a92
Change-Id: I53e7864b097cf9cff702e9185bb1c9091d97fe63
This commit is contained in:
@@ -482,6 +482,7 @@ interface IPackageManager {
|
||||
*/
|
||||
boolean performDexOpt(String packageName, boolean checkProfiles,
|
||||
int compileReason, boolean force);
|
||||
|
||||
/**
|
||||
* Ask the package manager to perform a dex-opt with the given compiler filter.
|
||||
*
|
||||
@@ -491,6 +492,16 @@ interface IPackageManager {
|
||||
boolean performDexOptMode(String packageName, boolean checkProfiles,
|
||||
String targetCompilerFilter, boolean force);
|
||||
|
||||
/**
|
||||
* Ask the package manager to perform a dex-opt with the given compiler filter on the
|
||||
* secondary dex files belonging to the given package.
|
||||
*
|
||||
* Note: exposed only for the shell command to allow moving packages explicitly to a
|
||||
* definite state.
|
||||
*/
|
||||
boolean performDexOptSecondary(String packageName,
|
||||
String targetCompilerFilter, boolean force);
|
||||
|
||||
/**
|
||||
* Ask the package manager to dump profiles associated with a package.
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,14 @@ public class Installer extends SystemService {
|
||||
public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
|
||||
/** Hint that the dexopt type is profile-guided. */
|
||||
public static final int DEXOPT_PROFILE_GUIDED = 1 << 5;
|
||||
/** The compilation is for a secondary dex file. */
|
||||
public static final int DEXOPT_SECONDARY_DEX = 1 << 6;
|
||||
/** Ignore the result of dexoptNeeded and force compilation. */
|
||||
public static final int DEXOPT_FORCE = 1 << 7;
|
||||
/** Indicates that the dex file passed to dexopt in on CE storage. */
|
||||
public static final int DEXOPT_STORAGE_CE = 1 << 8;
|
||||
/** Indicates that the dex file passed to dexopt in on DE storage. */
|
||||
public static final int DEXOPT_STORAGE_DE = 1 << 9;
|
||||
|
||||
// NOTE: keep in sync with installd
|
||||
public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.server.pm;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.os.Environment;
|
||||
import android.os.PowerManager;
|
||||
@@ -35,6 +36,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import dalvik.system.DexFile;
|
||||
|
||||
@@ -43,6 +45,10 @@ import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
|
||||
import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED;
|
||||
import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
|
||||
import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
|
||||
import static com.android.server.pm.Installer.DEXOPT_SECONDARY_DEX;
|
||||
import static com.android.server.pm.Installer.DEXOPT_FORCE;
|
||||
import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE;
|
||||
import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE;
|
||||
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
|
||||
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
|
||||
|
||||
@@ -52,13 +58,13 @@ import static dalvik.system.DexFile.isProfileGuidedCompilerFilter;
|
||||
/**
|
||||
* Helper class for running dexopt command on packages.
|
||||
*/
|
||||
class PackageDexOptimizer {
|
||||
public class PackageDexOptimizer {
|
||||
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_FAILED = -1;
|
||||
public static final int DEX_OPT_SKIPPED = 0;
|
||||
public static final int DEX_OPT_PERFORMED = 1;
|
||||
public static final int DEX_OPT_FAILED = -1;
|
||||
|
||||
private final Installer mInstaller;
|
||||
private final Object mInstallLock;
|
||||
@@ -100,6 +106,9 @@ class PackageDexOptimizer {
|
||||
return DEX_OPT_SKIPPED;
|
||||
}
|
||||
synchronized (mInstallLock) {
|
||||
// During boot the system doesn't need to instantiate and obtain a wake lock.
|
||||
// PowerManager might not be ready, but that doesn't mean that we can't proceed with
|
||||
// dexopt.
|
||||
final boolean useLock = mSystemReady;
|
||||
if (useLock) {
|
||||
mDexoptWakeLock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
|
||||
@@ -130,9 +139,11 @@ class PackageDexOptimizer {
|
||||
final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
|
||||
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
|
||||
|
||||
final String compilerFilter = getRealCompilerFilter(pkg, targetCompilerFilter);
|
||||
final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
|
||||
targetCompilerFilter, isUsedByOtherApps(pkg));
|
||||
final boolean profileUpdated = checkForProfileUpdates &&
|
||||
isProfileUpdated(pkg, sharedGid, compilerFilter);
|
||||
|
||||
// TODO(calin,jeffhao): shared library paths should be adjusted to include previous code
|
||||
// paths (b/34169257).
|
||||
final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
|
||||
@@ -200,6 +211,79 @@ class PackageDexOptimizer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs dexopt on the secondary dex {@code path} belonging to the app {@code info}.
|
||||
*
|
||||
* @return
|
||||
* DEX_OPT_FAILED if there was any exception during dexopt
|
||||
* DEX_OPT_PERFORMED if dexopt was performed successfully on the given path.
|
||||
* NOTE that DEX_OPT_PERFORMED for secondary dex files includes the case when the dex file
|
||||
* didn't need an update. That's because at the moment we don't get more than success/failure
|
||||
* from installd.
|
||||
*
|
||||
* TODO(calin): Consider adding return codes to installd dexopt invocation (rather than
|
||||
* throwing exceptions). Or maybe make a separate call to installd to get DexOptNeeded, though
|
||||
* that seems wasteful.
|
||||
*/
|
||||
public int dexOptSecondaryDexPath(ApplicationInfo info, String path, Set<String> isas,
|
||||
String compilerFilter, boolean isUsedByOtherApps) {
|
||||
synchronized (mInstallLock) {
|
||||
// During boot the system doesn't need to instantiate and obtain a wake lock.
|
||||
// PowerManager might not be ready, but that doesn't mean that we can't proceed with
|
||||
// dexopt.
|
||||
final boolean useLock = mSystemReady;
|
||||
if (useLock) {
|
||||
mDexoptWakeLock.setWorkSource(new WorkSource(info.uid));
|
||||
mDexoptWakeLock.acquire();
|
||||
}
|
||||
try {
|
||||
return dexOptSecondaryDexPathLI(info, path, isas, compilerFilter,
|
||||
isUsedByOtherApps);
|
||||
} finally {
|
||||
if (useLock) {
|
||||
mDexoptWakeLock.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mInstallLock")
|
||||
private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, Set<String> isas,
|
||||
String compilerFilter, boolean isUsedByOtherApps) {
|
||||
int dexoptFlags = getDexFlags(info, compilerFilter) | DEXOPT_SECONDARY_DEX;
|
||||
// Check the app storage and add the appropriate flags.
|
||||
if (info.dataDir.equals(info.deviceProtectedDataDir)) {
|
||||
dexoptFlags |= DEXOPT_STORAGE_DE;
|
||||
} else if (info.dataDir.equals(info.credentialProtectedDataDir)) {
|
||||
dexoptFlags |= DEXOPT_STORAGE_CE;
|
||||
} else {
|
||||
Slog.e(TAG, "Could not infer CE/DE storage for package " + info.packageName);
|
||||
return DEX_OPT_FAILED;
|
||||
}
|
||||
compilerFilter = getRealCompilerFilter(info, compilerFilter, isUsedByOtherApps);
|
||||
Log.d(TAG, "Running dexopt on: " + path
|
||||
+ " pkg=" + info.packageName + " isa=" + isas
|
||||
+ " dexoptFlags=" + printDexoptFlags(dexoptFlags)
|
||||
+ " target-filter=" + compilerFilter);
|
||||
|
||||
try {
|
||||
for (String isa : isas) {
|
||||
// Reuse the same dexopt path as for the primary apks. We don't need all the
|
||||
// arguments as some (dexopNeeded and oatDir) will be computed by installd because
|
||||
// system server cannot read untrusted app content.
|
||||
// TODO(calin): maybe add a separate call.
|
||||
mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
|
||||
/*oatDir*/ null, dexoptFlags,
|
||||
compilerFilter, info.volumeUuid, /*sharedLibrariesPath*/ null);
|
||||
}
|
||||
|
||||
return DEX_OPT_PERFORMED;
|
||||
} catch (InstallerException e) {
|
||||
Slog.w(TAG, "Failed to dexopt", e);
|
||||
return DEX_OPT_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the given dexopt-needed value. Can be overridden to influence the decision to
|
||||
* optimize or not (and in what way).
|
||||
@@ -246,8 +330,9 @@ class PackageDexOptimizer {
|
||||
* The target filter will be updated if the package code is used by other apps
|
||||
* or if it has the safe mode flag set.
|
||||
*/
|
||||
private String getRealCompilerFilter(PackageParser.Package pkg, String targetCompilerFilter) {
|
||||
int flags = pkg.applicationInfo.flags;
|
||||
private String getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter,
|
||||
boolean isUsedByOtherApps) {
|
||||
int flags = info.flags;
|
||||
boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
|
||||
if (vmSafeMode) {
|
||||
// For the compilation, it doesn't really matter what we return here because installd
|
||||
@@ -259,7 +344,7 @@ class PackageDexOptimizer {
|
||||
return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
|
||||
}
|
||||
|
||||
if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps(pkg)) {
|
||||
if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
|
||||
// If the dex files is used by other apps, we cannot use profile-guided compilation.
|
||||
return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
|
||||
}
|
||||
@@ -272,12 +357,16 @@ class PackageDexOptimizer {
|
||||
* filter.
|
||||
*/
|
||||
private int getDexFlags(PackageParser.Package pkg, String compilerFilter) {
|
||||
int flags = pkg.applicationInfo.flags;
|
||||
return getDexFlags(pkg.applicationInfo, compilerFilter);
|
||||
}
|
||||
|
||||
private int getDexFlags(ApplicationInfo info, String compilerFilter) {
|
||||
int flags = info.flags;
|
||||
boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
|
||||
boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
||||
// Profile guide compiled oat files should not be public.
|
||||
boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
|
||||
boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter;
|
||||
boolean isPublic = !info.isForwardLocked() && !isProfileGuidedFilter;
|
||||
int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
|
||||
int dexFlags =
|
||||
(isPublic ? DEXOPT_PUBLIC : 0)
|
||||
@@ -437,6 +526,19 @@ class PackageDexOptimizer {
|
||||
if ((flags & DEXOPT_SAFEMODE) == DEXOPT_SAFEMODE) {
|
||||
flagsList.add("safemode");
|
||||
}
|
||||
if ((flags & DEXOPT_SECONDARY_DEX) == DEXOPT_SECONDARY_DEX) {
|
||||
flagsList.add("secondary");
|
||||
}
|
||||
if ((flags & DEXOPT_FORCE) == DEXOPT_FORCE) {
|
||||
flagsList.add("force");
|
||||
}
|
||||
if ((flags & DEXOPT_STORAGE_CE) == DEXOPT_STORAGE_CE) {
|
||||
flagsList.add("storage_ce");
|
||||
}
|
||||
if ((flags & DEXOPT_STORAGE_DE) == DEXOPT_STORAGE_DE) {
|
||||
flagsList.add("storage_de");
|
||||
}
|
||||
|
||||
return String.join(",", flagsList);
|
||||
}
|
||||
|
||||
@@ -461,5 +563,12 @@ class PackageDexOptimizer {
|
||||
// TODO: The return value is wrong when patchoat is needed.
|
||||
return DexFile.DEX2OAT_FROM_SCRATCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int adjustDexoptFlags(int flags) {
|
||||
// Add DEXOPT_FORCE flag to signal installd that it should force compilation
|
||||
// and discard dexoptanalyzer result.
|
||||
return flags | DEXOPT_FORCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2133,7 +2133,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
mInstaller = installer;
|
||||
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
|
||||
"*dexopt*");
|
||||
mDexManager = new DexManager();
|
||||
mDexManager = new DexManager(this, mPackageDexOptimizer);
|
||||
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
|
||||
|
||||
mOnPermissionChangeListeners = new OnPermissionChangeListeners(
|
||||
@@ -7540,6 +7540,15 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
targetCompilerFilter, getOrCreateCompilerPackageStats(p));
|
||||
}
|
||||
|
||||
// Performs dexopt on the used secondary dex files belonging to the given package.
|
||||
// Returns true if all dex files were process successfully (which could mean either dexopt or
|
||||
// skip). Returns false if any of the files caused errors.
|
||||
@Override
|
||||
public boolean performDexOptSecondary(String packageName, String compilerFilter,
|
||||
boolean force) {
|
||||
return mDexManager.dexoptSecondaryDex(packageName, compilerFilter, force);
|
||||
}
|
||||
|
||||
Collection<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
|
||||
if (p.usesLibraries != null || p.usesOptionalLibraries != null) {
|
||||
ArrayList<PackageParser.Package> retValue = new ArrayList<>();
|
||||
|
||||
@@ -23,7 +23,7 @@ import dalvik.system.DexFile;
|
||||
/**
|
||||
* Manage (retrieve) mappings from compilation reason to compilation filter.
|
||||
*/
|
||||
class PackageManagerServiceCompilerMapping {
|
||||
public class PackageManagerServiceCompilerMapping {
|
||||
// Names for compilation reasons.
|
||||
static final String REASON_STRINGS[] = {
|
||||
"first-boot", "boot", "install", "bg-dexopt", "ab-ota", "nsys-library", "shared-apk",
|
||||
|
||||
@@ -288,6 +288,7 @@ class PackageManagerShellCommand extends ShellCommand {
|
||||
String compilerFilter = null;
|
||||
String compilationReason = null;
|
||||
String checkProfilesRaw = null;
|
||||
boolean secondaryDex = false;
|
||||
|
||||
String opt;
|
||||
while ((opt = getNextOption()) != null) {
|
||||
@@ -315,6 +316,9 @@ class PackageManagerShellCommand extends ShellCommand {
|
||||
clearProfileData = true;
|
||||
compilationReason = "install";
|
||||
break;
|
||||
case "--secondary-dex":
|
||||
secondaryDex = true;
|
||||
break;
|
||||
default:
|
||||
pw.println("Error: Unknown option: " + opt);
|
||||
return 1;
|
||||
@@ -387,8 +391,11 @@ class PackageManagerShellCommand extends ShellCommand {
|
||||
mInterface.clearApplicationProfileData(packageName);
|
||||
}
|
||||
|
||||
boolean result = mInterface.performDexOptMode(packageName,
|
||||
checkProfiles, targetCompilerFilter, forceCompilation);
|
||||
boolean result = secondaryDex
|
||||
? mInterface.performDexOptSecondary(packageName,
|
||||
targetCompilerFilter, forceCompilation)
|
||||
: mInterface.performDexOptMode(packageName,
|
||||
checkProfiles, targetCompilerFilter, forceCompilation);
|
||||
if (!result) {
|
||||
failedPackages.add(packageName);
|
||||
}
|
||||
@@ -1448,6 +1455,7 @@ class PackageManagerShellCommand extends ShellCommand {
|
||||
}
|
||||
pw.println(" --reset: restore package to its post-install state");
|
||||
pw.println(" --check-prof (true | false): look at profiles when doing dexopt?");
|
||||
pw.println(" --secondary-dex: copmile app secondary dex files");
|
||||
pw.println(" list features");
|
||||
pw.println(" Prints all features of the system.");
|
||||
pw.println(" list instrumentation [-f] [TARGET-PACKAGE]");
|
||||
|
||||
@@ -16,13 +16,16 @@
|
||||
|
||||
package com.android.server.pm.dex;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.pm.PackageDexOptimizer;
|
||||
import com.android.server.pm.PackageManagerServiceUtils;
|
||||
import com.android.server.pm.PackageManagerServiceCompilerMapping;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -32,6 +35,9 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
|
||||
import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
|
||||
|
||||
/**
|
||||
* This class keeps track of how dex files are used.
|
||||
* Every time it gets a notification about a dex file being loaded it tracks
|
||||
@@ -54,15 +60,20 @@ public class DexManager {
|
||||
// encode and save the dex usage data.
|
||||
private final PackageDexUsage mPackageDexUsage;
|
||||
|
||||
private final IPackageManager mPackageManager;
|
||||
private final PackageDexOptimizer mPackageDexOptimizer;
|
||||
|
||||
// Possible outcomes of a dex search.
|
||||
private static int DEX_SEARCH_NOT_FOUND = 0; // dex file not found
|
||||
private static int DEX_SEARCH_FOUND_PRIMARY = 1; // dex file is the primary/base apk
|
||||
private static int DEX_SEARCH_FOUND_SPLIT = 2; // dex file is a split apk
|
||||
private static int DEX_SEARCH_FOUND_SECONDARY = 3; // dex file is a secondary dex
|
||||
|
||||
public DexManager() {
|
||||
public DexManager(IPackageManager pms, PackageDexOptimizer pdo) {
|
||||
mPackageCodeLocationsCache = new HashMap<>();
|
||||
mPackageDexUsage = new PackageDexUsage();
|
||||
mPackageManager = pms;
|
||||
mPackageDexOptimizer = pdo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -199,10 +210,61 @@ public class DexManager {
|
||||
* Get the package dex usage for the given package name.
|
||||
* @return the package data or null if there is no data available for this package.
|
||||
*/
|
||||
public PackageDexUsage.PackageUseInfo getPackageUseInfo(String packageName) {
|
||||
public PackageUseInfo getPackageUseInfo(String packageName) {
|
||||
return mPackageDexUsage.getPackageUseInfo(packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform dexopt on the package {@code packageName} secondary dex files.
|
||||
* @return true if all secondary dex files were processed successfully (compiled or skipped
|
||||
* because they don't need to be compiled)..
|
||||
*/
|
||||
public boolean dexoptSecondaryDex(String packageName, String compilerFilter, boolean force) {
|
||||
// Select the dex optimizer based on the force parameter.
|
||||
// Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust
|
||||
// the necessary dexopt flags to make sure that compilation is not skipped. This avoid
|
||||
// passing the force flag through the multitude of layers.
|
||||
// Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
|
||||
// allocate an object here.
|
||||
PackageDexOptimizer pdo = force
|
||||
? new PackageDexOptimizer.ForcedUpdatePackageDexOptimizer(mPackageDexOptimizer)
|
||||
: mPackageDexOptimizer;
|
||||
PackageUseInfo useInfo = getPackageUseInfo(packageName);
|
||||
if (useInfo == null || useInfo.getDexUseInfoMap().isEmpty()) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "No secondary dex use for package:" + packageName);
|
||||
}
|
||||
// Nothing to compile, return true.
|
||||
return true;
|
||||
}
|
||||
boolean success = true;
|
||||
for (Map.Entry<String, DexUseInfo> entry : useInfo.getDexUseInfoMap().entrySet()) {
|
||||
String dexPath = entry.getKey();
|
||||
DexUseInfo dexUseInfo = entry.getValue();
|
||||
PackageInfo pkg = null;
|
||||
try {
|
||||
pkg = mPackageManager.getPackageInfo(packageName, /*flags*/0,
|
||||
dexUseInfo.getOwnerUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
// It may be that the package gets uninstalled while we try to compile its
|
||||
// secondary dex files. If that's the case, just ignore.
|
||||
// Note that we don't break the entire loop because the package might still be
|
||||
// installed for other users.
|
||||
if (pkg == null) {
|
||||
Slog.d(TAG, "Could not find package when compiling secondary dex " + packageName
|
||||
+ " for user " + dexUseInfo.getOwnerUserId());
|
||||
// Skip over it, another user might still have the package.
|
||||
continue;
|
||||
}
|
||||
int result = pdo.dexOptSecondaryDexPath(pkg.applicationInfo, dexPath,
|
||||
dexUseInfo.getLoaderIsas(), compilerFilter, dexUseInfo.isUsedByOtherApps());
|
||||
success = success && (result != PackageDexOptimizer.DEX_OPT_FAILED);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the package which owns the given dexPath.
|
||||
*/
|
||||
|
||||
@@ -73,8 +73,7 @@ public class DexManagerTests {
|
||||
mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0);
|
||||
mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1);
|
||||
|
||||
|
||||
mDexManager = new DexManager();
|
||||
mDexManager = new DexManager(null, null);
|
||||
|
||||
// Foo and Bar are available to user0.
|
||||
// Only Bar is available to user1;
|
||||
|
||||
Reference in New Issue
Block a user