Merge "Frameworks/base: Propagate boot status to installd" into mnc-dr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b49245f962
@@ -92,14 +92,14 @@ public class InstallerConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int dexopt(String apkPath, int uid, boolean isPublic,
|
public int dexopt(String apkPath, int uid, boolean isPublic,
|
||||||
String instructionSet, int dexoptNeeded) {
|
String instructionSet, int dexoptNeeded, boolean bootComplete) {
|
||||||
return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded,
|
return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded,
|
||||||
false, false, null);
|
false, false, null, bootComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
|
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
|
||||||
String instructionSet, int dexoptNeeded, boolean vmSafeMode,
|
String instructionSet, int dexoptNeeded, boolean vmSafeMode,
|
||||||
boolean debuggable, String outputPath) {
|
boolean debuggable, String outputPath, boolean bootComplete) {
|
||||||
StringBuilder builder = new StringBuilder("dexopt");
|
StringBuilder builder = new StringBuilder("dexopt");
|
||||||
builder.append(' ');
|
builder.append(' ');
|
||||||
builder.append(apkPath);
|
builder.append(apkPath);
|
||||||
@@ -116,6 +116,7 @@ public class InstallerConnection {
|
|||||||
builder.append(debuggable ? " 1" : " 0");
|
builder.append(debuggable ? " 1" : " 0");
|
||||||
builder.append(' ');
|
builder.append(' ');
|
||||||
builder.append(outputPath != null ? outputPath : "!");
|
builder.append(outputPath != null ? outputPath : "!");
|
||||||
|
builder.append(bootComplete ? " 1" : " 0");
|
||||||
return execute(builder.toString());
|
return execute(builder.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -477,7 +477,7 @@ public class ZygoteInit {
|
|||||||
classPathElement, "*", instructionSet, false /* defer */);
|
classPathElement, "*", instructionSet, false /* defer */);
|
||||||
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
|
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
|
||||||
installer.dexopt(classPathElement, Process.SYSTEM_UID, false,
|
installer.dexopt(classPathElement, Process.SYSTEM_UID, false,
|
||||||
instructionSet, dexoptNeeded);
|
instructionSet, dexoptNeeded, false /* boot complete */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
|
|||||||
@@ -77,24 +77,37 @@ public final class Installer extends SystemService {
|
|||||||
|
|
||||||
public int dexopt(String apkPath, int uid, boolean isPublic,
|
public int dexopt(String apkPath, int uid, boolean isPublic,
|
||||||
String instructionSet, int dexoptNeeded) {
|
String instructionSet, int dexoptNeeded) {
|
||||||
|
return dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int dexopt(String apkPath, int uid, boolean isPublic,
|
||||||
|
String instructionSet, int dexoptNeeded, boolean bootComplete) {
|
||||||
if (!isValidInstructionSet(instructionSet)) {
|
if (!isValidInstructionSet(instructionSet)) {
|
||||||
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
|
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded);
|
return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded,
|
||||||
|
bootComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
|
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
|
||||||
String instructionSet, int dexoptNeeded, boolean vmSafeMode,
|
String instructionSet, int dexoptNeeded, boolean vmSafeMode,
|
||||||
boolean debuggable, @Nullable String outputPath) {
|
boolean debuggable, @Nullable String outputPath) {
|
||||||
|
return dexopt(apkPath, uid, isPublic, pkgName, instructionSet, dexoptNeeded, vmSafeMode,
|
||||||
|
debuggable, outputPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
|
||||||
|
String instructionSet, int dexoptNeeded, boolean vmSafeMode,
|
||||||
|
boolean debuggable, @Nullable String outputPath, boolean bootComplete) {
|
||||||
if (!isValidInstructionSet(instructionSet)) {
|
if (!isValidInstructionSet(instructionSet)) {
|
||||||
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
|
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return mInstaller.dexopt(apkPath, uid, isPublic, pkgName,
|
return mInstaller.dexopt(apkPath, uid, isPublic, pkgName,
|
||||||
instructionSet, dexoptNeeded, vmSafeMode,
|
instructionSet, dexoptNeeded, vmSafeMode,
|
||||||
debuggable, outputPath);
|
debuggable, outputPath, bootComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int idmap(String targetApkPath, String overlayApkPath, int uid) {
|
public int idmap(String targetApkPath, String overlayApkPath, int uid) {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ final class PackageDexOptimizer {
|
|||||||
* {@link PackageManagerService#mInstallLock}.
|
* {@link PackageManagerService#mInstallLock}.
|
||||||
*/
|
*/
|
||||||
int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
|
int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
|
||||||
boolean forceDex, boolean defer, boolean inclDependencies) {
|
boolean forceDex, boolean defer, boolean inclDependencies, boolean bootComplete) {
|
||||||
ArraySet<String> done;
|
ArraySet<String> done;
|
||||||
if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
|
if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
|
||||||
done = new ArraySet<String>();
|
done = new ArraySet<String>();
|
||||||
@@ -86,7 +86,7 @@ final class PackageDexOptimizer {
|
|||||||
mDexoptWakeLock.acquire();
|
mDexoptWakeLock.acquire();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
|
return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete, done);
|
||||||
} finally {
|
} finally {
|
||||||
if (useLock) {
|
if (useLock) {
|
||||||
mDexoptWakeLock.release();
|
mDexoptWakeLock.release();
|
||||||
@@ -96,18 +96,19 @@ final class PackageDexOptimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
|
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
|
||||||
boolean forceDex, boolean defer, ArraySet<String> done) {
|
boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) {
|
||||||
final String[] instructionSets = targetInstructionSets != null ?
|
final String[] instructionSets = targetInstructionSets != null ?
|
||||||
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
|
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
|
||||||
|
|
||||||
if (done != null) {
|
if (done != null) {
|
||||||
done.add(pkg.packageName);
|
done.add(pkg.packageName);
|
||||||
if (pkg.usesLibraries != null) {
|
if (pkg.usesLibraries != null) {
|
||||||
performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
|
performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer,
|
||||||
|
bootComplete, done);
|
||||||
}
|
}
|
||||||
if (pkg.usesOptionalLibraries != null) {
|
if (pkg.usesOptionalLibraries != null) {
|
||||||
performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer,
|
performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer,
|
||||||
done);
|
bootComplete, done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,11 +175,11 @@ final class PackageDexOptimizer {
|
|||||||
Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
|
Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
|
||||||
+ pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
|
+ pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
|
||||||
+ " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
|
+ " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
|
||||||
+ " oatDir = " + oatDir);
|
+ " oatDir = " + oatDir + " bootComplete=" + bootComplete);
|
||||||
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
|
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
|
||||||
final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
|
final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
|
||||||
!pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
|
!pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
|
||||||
dexoptNeeded, vmSafeMode, debuggable, oatDir);
|
dexoptNeeded, vmSafeMode, debuggable, oatDir, bootComplete);
|
||||||
|
|
||||||
// Dex2oat might fail due to compiler / verifier errors. We soldier on
|
// Dex2oat might fail due to compiler / verifier errors. We soldier on
|
||||||
// regardless, and attempt to interpret the app as a safety net.
|
// regardless, and attempt to interpret the app as a safety net.
|
||||||
@@ -235,12 +236,12 @@ final class PackageDexOptimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
|
private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
|
||||||
boolean forceDex, boolean defer, ArraySet<String> done) {
|
boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) {
|
||||||
for (String libName : libs) {
|
for (String libName : libs) {
|
||||||
PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
|
PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
|
||||||
libName);
|
libName);
|
||||||
if (libPkg != null && !done.contains(libName)) {
|
if (libPkg != null && !done.contains(libName)) {
|
||||||
performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
|
performDexOptLI(libPkg, instructionSets, forceDex, defer, bootComplete, done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1979,7 +1979,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
|
int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
|
||||||
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
|
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
|
||||||
alreadyDexOpted.add(lib);
|
alreadyDexOpted.add(lib);
|
||||||
mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded);
|
mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false);
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Slog.w(TAG, "Library not found: " + lib);
|
Slog.w(TAG, "Library not found: " + lib);
|
||||||
@@ -2027,7 +2027,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
try {
|
try {
|
||||||
int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
|
int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
|
||||||
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
|
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
|
||||||
mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded);
|
mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false);
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Slog.w(TAG, "Jar not found: " + path);
|
Slog.w(TAG, "Jar not found: " + path);
|
||||||
@@ -2256,7 +2256,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
// the rest of the commands above) because there's precious little we
|
// the rest of the commands above) because there's precious little we
|
||||||
// can do about it. A settings error is reported, though.
|
// can do about it. A settings error is reported, though.
|
||||||
adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,
|
adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,
|
||||||
false /* force dexopt */, false /* defer dexopt */);
|
false /* force dexopt */, false /* defer dexopt */,
|
||||||
|
false /* boot complete */);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we know all the packages we are keeping,
|
// Now that we know all the packages we are keeping,
|
||||||
@@ -6208,7 +6209,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
PackageParser.Package p = pkg;
|
PackageParser.Package p = pkg;
|
||||||
synchronized (mInstallLock) {
|
synchronized (mInstallLock) {
|
||||||
mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */,
|
mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */,
|
||||||
false /* force dex */, false /* defer */, true /* include dependencies */);
|
false /* force dex */, false /* defer */, true /* include dependencies */,
|
||||||
|
false /* boot complete */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6251,7 +6253,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
synchronized (mInstallLock) {
|
synchronized (mInstallLock) {
|
||||||
final String[] instructionSets = new String[] { targetInstructionSet };
|
final String[] instructionSets = new String[] { targetInstructionSet };
|
||||||
int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
|
int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
|
||||||
false /* forceDex */, false /* defer */, true /* inclDependencies */);
|
false /* forceDex */, false /* defer */, true /* inclDependencies */,
|
||||||
|
true /* boot complete */);
|
||||||
return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
|
return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -6298,7 +6301,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
final String[] instructionSets = new String[] {
|
final String[] instructionSets = new String[] {
|
||||||
getPrimaryInstructionSet(pkg.applicationInfo) };
|
getPrimaryInstructionSet(pkg.applicationInfo) };
|
||||||
final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
|
final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
|
||||||
true /*forceDex*/, false /* defer */, true /* inclDependencies */);
|
true /*forceDex*/, false /* defer */, true /* inclDependencies */,
|
||||||
|
true /* boot complete */);
|
||||||
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
|
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
|
||||||
throw new IllegalStateException("Failed to dexopt: " + res);
|
throw new IllegalStateException("Failed to dexopt: " + res);
|
||||||
}
|
}
|
||||||
@@ -7090,12 +7094,13 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
// we can avoid redundant dexopts, and also to make sure we've got the
|
// we can avoid redundant dexopts, and also to make sure we've got the
|
||||||
// code and package path correct.
|
// code and package path correct.
|
||||||
adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
|
adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
|
||||||
pkg, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0);
|
pkg, forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, true /* boot complete */);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((scanFlags & SCAN_NO_DEX) == 0) {
|
if ((scanFlags & SCAN_NO_DEX) == 0) {
|
||||||
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
|
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
|
||||||
forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */);
|
forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */,
|
||||||
|
(scanFlags & SCAN_BOOTING) == 0);
|
||||||
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
|
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
|
||||||
throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI");
|
throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI");
|
||||||
}
|
}
|
||||||
@@ -7171,7 +7176,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
PackageParser.Package clientPkg = clientLibPkgs.get(i);
|
PackageParser.Package clientPkg = clientLibPkgs.get(i);
|
||||||
int result = mPackageDexOptimizer.performDexOpt(clientPkg,
|
int result = mPackageDexOptimizer.performDexOpt(clientPkg,
|
||||||
null /* instruction sets */, forceDex,
|
null /* instruction sets */, forceDex,
|
||||||
(scanFlags & SCAN_DEFER_DEX) != 0, false);
|
(scanFlags & SCAN_DEFER_DEX) != 0, false,
|
||||||
|
(scanFlags & SCAN_BOOTING) == 0);
|
||||||
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
|
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
|
||||||
throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
|
throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
|
||||||
"scanPackageLI failed to dexopt clientLibPkgs");
|
"scanPackageLI failed to dexopt clientLibPkgs");
|
||||||
@@ -7712,7 +7718,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
* adds unnecessary complexity.
|
* adds unnecessary complexity.
|
||||||
*/
|
*/
|
||||||
private void adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
|
private void adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
|
||||||
PackageParser.Package scannedPackage, boolean forceDexOpt, boolean deferDexOpt) {
|
PackageParser.Package scannedPackage, boolean forceDexOpt, boolean deferDexOpt,
|
||||||
|
boolean bootComplete) {
|
||||||
String requiredInstructionSet = null;
|
String requiredInstructionSet = null;
|
||||||
if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
|
if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
|
||||||
requiredInstructionSet = VMRuntime.getInstructionSet(
|
requiredInstructionSet = VMRuntime.getInstructionSet(
|
||||||
@@ -7776,7 +7783,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
|
Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
|
||||||
|
|
||||||
int result = mPackageDexOptimizer.performDexOpt(ps.pkg,
|
int result = mPackageDexOptimizer.performDexOpt(ps.pkg,
|
||||||
null /* instruction sets */, forceDexOpt, deferDexOpt, true);
|
null /* instruction sets */, forceDexOpt, deferDexOpt, true,
|
||||||
|
bootComplete);
|
||||||
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
|
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
|
||||||
ps.primaryCpuAbiString = null;
|
ps.primaryCpuAbiString = null;
|
||||||
ps.pkg.applicationInfo.primaryCpuAbi = null;
|
ps.pkg.applicationInfo.primaryCpuAbi = null;
|
||||||
@@ -12376,7 +12384,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
// Run dexopt before old package gets removed, to minimize time when app is unavailable
|
// Run dexopt before old package gets removed, to minimize time when app is unavailable
|
||||||
int result = mPackageDexOptimizer
|
int result = mPackageDexOptimizer
|
||||||
.performDexOpt(pkg, null /* instruction sets */, false /* forceDex */,
|
.performDexOpt(pkg, null /* instruction sets */, false /* forceDex */,
|
||||||
false /* defer */, false /* inclDependencies */);
|
false /* defer */, false /* inclDependencies */,
|
||||||
|
true /* boot complete */);
|
||||||
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
|
if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
|
||||||
res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);
|
res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user