Merge "Reduce app size by downgrading inactive apps"
This commit is contained in:
@@ -513,7 +513,7 @@ interface IPackageManager {
|
||||
* configuration.
|
||||
*/
|
||||
boolean performDexOpt(String packageName, boolean checkProfiles,
|
||||
int compileReason, boolean force, boolean bootComplete);
|
||||
int compileReason, boolean force, boolean bootComplete, boolean downgrade);
|
||||
|
||||
/**
|
||||
* Ask the package manager to perform a dex-opt with the given compiler filter.
|
||||
|
||||
@@ -577,7 +577,7 @@ public class ZygoteInit {
|
||||
try {
|
||||
installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
|
||||
instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
|
||||
uuid, sharedLibraries, seInfo);
|
||||
uuid, sharedLibraries, seInfo, false /* downgrade */);
|
||||
} catch (RemoteException | ServiceSpecificException e) {
|
||||
// Ignore (but log), we need this on the classpath for fallback mode.
|
||||
Log.w(TAG, "Failed compiling classpath element for system server: "
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.server.pm;
|
||||
|
||||
import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobParameters;
|
||||
import android.app.job.JobScheduler;
|
||||
@@ -40,6 +39,7 @@ import com.android.server.LocalServices;
|
||||
import com.android.server.PinnerService;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -73,6 +73,9 @@ public class BackgroundDexOptService extends JobService {
|
||||
// Optimizations should be aborted. No space left on device.
|
||||
private static final int OPTIMIZE_ABORT_NO_SPACE_LEFT = 3;
|
||||
|
||||
// Used for calculating space threshold for downgrading unused apps.
|
||||
private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2;
|
||||
|
||||
/**
|
||||
* Set of failed packages remembered across job runs.
|
||||
*/
|
||||
@@ -92,6 +95,9 @@ public class BackgroundDexOptService extends JobService {
|
||||
|
||||
private final File mDataDir = Environment.getDataDirectory();
|
||||
|
||||
private static final long mDowngradeUnusedAppsThresholdInMillis =
|
||||
getDowngradeUnusedAppsThresholdInMillis();
|
||||
|
||||
public static void schedule(Context context) {
|
||||
JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
|
||||
@@ -215,7 +221,8 @@ public class BackgroundDexOptService extends JobService {
|
||||
/* checkProfiles */ false,
|
||||
PackageManagerService.REASON_BOOT,
|
||||
/* force */ false,
|
||||
/* bootComplete */ true);
|
||||
/* bootComplete */ true,
|
||||
/* downgrade */ false);
|
||||
if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
|
||||
updatedPackages.add(pkg);
|
||||
}
|
||||
@@ -243,7 +250,8 @@ public class BackgroundDexOptService extends JobService {
|
||||
}
|
||||
|
||||
// Optimize the given packages and return the optimization result (one of the OPTIMIZE_* codes).
|
||||
private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs, Context context) {
|
||||
private int idleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
|
||||
Context context) {
|
||||
Log.i(TAG, "Performing idle optimizations");
|
||||
// If post-boot update is still running, request that it exits early.
|
||||
mExitPostBootUpdate.set(true);
|
||||
@@ -274,9 +282,16 @@ public class BackgroundDexOptService extends JobService {
|
||||
long lowStorageThreshold, boolean is_for_primary_dex,
|
||||
ArraySet<String> failedPackageNames) {
|
||||
ArraySet<String> updatedPackages = new ArraySet<>();
|
||||
Set<String> unusedPackages = pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
|
||||
// Only downgrade apps when space is low on device.
|
||||
// Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
|
||||
// up disk before user hits the actual lowStorageThreshold.
|
||||
final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE *
|
||||
lowStorageThreshold;
|
||||
boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
|
||||
for (String pkg : pkgs) {
|
||||
int abort_code = abortIdleOptimizations(lowStorageThreshold);
|
||||
if (abort_code != OPTIMIZE_CONTINUE) {
|
||||
if (abort_code == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
|
||||
return abort_code;
|
||||
}
|
||||
|
||||
@@ -284,30 +299,57 @@ public class BackgroundDexOptService extends JobService {
|
||||
if (failedPackageNames.contains(pkg)) {
|
||||
// Skip previously failing package
|
||||
continue;
|
||||
} else {
|
||||
// Conservatively add package to the list of failing ones in case performDexOpt
|
||||
// never returns.
|
||||
failedPackageNames.add(pkg);
|
||||
}
|
||||
}
|
||||
|
||||
int reason;
|
||||
boolean downgrade;
|
||||
// Downgrade unused packages.
|
||||
if (unusedPackages.contains(pkg) && shouldDowngrade) {
|
||||
// This applies for system apps or if packages location is not a directory, i.e.
|
||||
// monolithic install.
|
||||
if (is_for_primary_dex && !pm.canHaveOatDir(pkg)) {
|
||||
// For apps that don't have the oat directory, instead of downgrading,
|
||||
// remove their compiler artifacts from dalvik cache.
|
||||
pm.deleteOatArtifactsOfPackage(pkg);
|
||||
continue;
|
||||
} else {
|
||||
reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE;
|
||||
downgrade = true;
|
||||
}
|
||||
} else if (abort_code != OPTIMIZE_ABORT_NO_SPACE_LEFT) {
|
||||
reason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
|
||||
downgrade = false;
|
||||
} else {
|
||||
// can't dexopt because of low space.
|
||||
continue;
|
||||
}
|
||||
|
||||
synchronized (failedPackageNames) {
|
||||
// Conservatively add package to the list of failing ones in case
|
||||
// performDexOpt never returns.
|
||||
failedPackageNames.add(pkg);
|
||||
}
|
||||
|
||||
// Optimize package if needed. Note that there can be no race between
|
||||
// concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
|
||||
boolean success;
|
||||
if (is_for_primary_dex) {
|
||||
int result = pm.performDexOptWithStatus(pkg,
|
||||
/* checkProfiles */ true,
|
||||
PackageManagerService.REASON_BACKGROUND_DEXOPT,
|
||||
/* force */ false,
|
||||
/* bootComplete */ true);
|
||||
reason,
|
||||
false /* forceCompile*/,
|
||||
true /* bootComplete */,
|
||||
downgrade);
|
||||
success = result != PackageDexOptimizer.DEX_OPT_FAILED;
|
||||
if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
|
||||
updatedPackages.add(pkg);
|
||||
}
|
||||
} else {
|
||||
success = pm.performDexOptSecondary(pkg,
|
||||
PackageManagerService.REASON_BACKGROUND_DEXOPT,
|
||||
/* force */ false);
|
||||
reason,
|
||||
false /* force */,
|
||||
downgrade);
|
||||
}
|
||||
if (success) {
|
||||
// Dexopt succeeded, remove package from the list of failing ones.
|
||||
@@ -347,6 +389,16 @@ public class BackgroundDexOptService extends JobService {
|
||||
return OPTIMIZE_CONTINUE;
|
||||
}
|
||||
|
||||
// Evaluate whether apps should be downgraded.
|
||||
private boolean shouldDowngrade(long lowStorageThresholdForDowngrade) {
|
||||
long usableSpace = mDataDir.getUsableSpace();
|
||||
if (usableSpace < lowStorageThresholdForDowngrade) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the idle optimizations immediately.
|
||||
*/
|
||||
@@ -415,4 +467,14 @@ public class BackgroundDexOptService extends JobService {
|
||||
pinnerService.update(updatedPackages);
|
||||
}
|
||||
}
|
||||
|
||||
private static long getDowngradeUnusedAppsThresholdInMillis() {
|
||||
final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days";
|
||||
String sysPropValue = SystemProperties.get(sysPropKey);
|
||||
if (sysPropValue == null || sysPropValue.isEmpty()) {
|
||||
Log.w(TAG, "SysProp " + sysPropKey + " not set");
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,13 +279,13 @@ public class Installer extends SystemService {
|
||||
public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
|
||||
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
|
||||
String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
|
||||
@Nullable String seInfo)
|
||||
@Nullable String seInfo, boolean downgrade)
|
||||
throws InstallerException {
|
||||
assertValidInstructionSet(instructionSet);
|
||||
if (!checkBeforeRemote()) return;
|
||||
try {
|
||||
mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
|
||||
dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo);
|
||||
dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade);
|
||||
} catch (Exception e) {
|
||||
throw InstallerException.from(e);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import android.os.ResultReceiver;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
@@ -40,7 +39,6 @@ import com.android.server.pm.Installer.InstallerException;
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -261,11 +259,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
public void dexopt(String apkPath, int uid, @Nullable String pkgName,
|
||||
String instructionSet, int dexoptNeeded, @Nullable String outputPath,
|
||||
int dexFlags, String compilerFilter, @Nullable String volumeUuid,
|
||||
@Nullable String sharedLibraries, @Nullable String seInfo) throws InstallerException {
|
||||
@Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade)
|
||||
throws InstallerException {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
// The version. Right now it's 2.
|
||||
builder.append("2 ");
|
||||
// The version. Right now it's 3.
|
||||
builder.append("3 ");
|
||||
|
||||
builder.append("dexopt");
|
||||
|
||||
@@ -280,6 +279,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
encodeParameter(builder, volumeUuid);
|
||||
encodeParameter(builder, sharedLibraries);
|
||||
encodeParameter(builder, seInfo);
|
||||
encodeParameter(builder, downgrade);
|
||||
|
||||
commands.add(builder.toString());
|
||||
}
|
||||
@@ -319,12 +319,14 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
|
||||
getCompilerFilterForReason(compilationReason),
|
||||
null /* CompilerStats.PackageStats */,
|
||||
mPackageManagerService.getDexManager().isUsedByOtherApps(pkg.packageName),
|
||||
true /* bootComplete */);
|
||||
true /* bootComplete */,
|
||||
false /* downgrade */);
|
||||
|
||||
mPackageManagerService.getDexManager().dexoptSecondaryDex(pkg.packageName,
|
||||
getCompilerFilterForReason(compilationReason),
|
||||
false /* force */,
|
||||
false /* compileOnlySharedDex */);
|
||||
false /* compileOnlySharedDex */,
|
||||
false /* downgrade */);
|
||||
return commands;
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ public class PackageDexOptimizer {
|
||||
int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
|
||||
String[] instructionSets, boolean checkProfiles, String targetCompilationFilter,
|
||||
CompilerStats.PackageStats packageStats, boolean isUsedByOtherApps,
|
||||
boolean bootComplete) {
|
||||
boolean bootComplete, boolean downgrade) {
|
||||
if (!canOptimizePackage(pkg)) {
|
||||
return DEX_OPT_SKIPPED;
|
||||
}
|
||||
@@ -133,7 +133,8 @@ public class PackageDexOptimizer {
|
||||
final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid);
|
||||
try {
|
||||
return performDexOptLI(pkg, sharedLibraries, instructionSets, checkProfiles,
|
||||
targetCompilationFilter, packageStats, isUsedByOtherApps, bootComplete);
|
||||
targetCompilationFilter, packageStats, isUsedByOtherApps, bootComplete,
|
||||
downgrade);
|
||||
} finally {
|
||||
releaseWakeLockLI(acquireTime);
|
||||
}
|
||||
@@ -148,7 +149,7 @@ public class PackageDexOptimizer {
|
||||
private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
|
||||
String[] targetInstructionSets, boolean checkForProfileUpdates,
|
||||
String targetCompilerFilter, CompilerStats.PackageStats packageStats,
|
||||
boolean isUsedByOtherApps, boolean bootComplete) {
|
||||
boolean isUsedByOtherApps, boolean bootComplete, boolean downgrade) {
|
||||
final String[] instructionSets = targetInstructionSets != null ?
|
||||
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
|
||||
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
|
||||
@@ -185,7 +186,8 @@ public class PackageDexOptimizer {
|
||||
}
|
||||
for (String dexCodeIsa : dexCodeInstructionSets) {
|
||||
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, profileUpdated,
|
||||
sharedLibrariesPathWithSplits, dexoptFlags, sharedGid, packageStats);
|
||||
sharedLibrariesPathWithSplits, dexoptFlags, sharedGid, packageStats,
|
||||
downgrade);
|
||||
// The end result is:
|
||||
// - FAILED if any path failed,
|
||||
// - PERFORMED if at least one path needed compilation,
|
||||
@@ -209,8 +211,8 @@ public class PackageDexOptimizer {
|
||||
@GuardedBy("mInstallLock")
|
||||
private int dexOptPath(PackageParser.Package pkg, String path, String isa,
|
||||
String compilerFilter, boolean profileUpdated, String sharedLibrariesPath,
|
||||
int dexoptFlags, int uid, CompilerStats.PackageStats packageStats) {
|
||||
int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, profileUpdated);
|
||||
int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade) {
|
||||
int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, profileUpdated, downgrade);
|
||||
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
|
||||
return DEX_OPT_SKIPPED;
|
||||
}
|
||||
@@ -229,8 +231,12 @@ public class PackageDexOptimizer {
|
||||
try {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
// TODO: Consider adding 2 different APIs for primary and secondary dexopt.
|
||||
// installd only uses downgrade flag for secondary dex files and ignores it for
|
||||
// primary dex files.
|
||||
mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
|
||||
compilerFilter, pkg.volumeUuid, sharedLibrariesPath, pkg.applicationInfo.seInfo);
|
||||
compilerFilter, pkg.volumeUuid, sharedLibrariesPath, pkg.applicationInfo.seInfo,
|
||||
false /* downgrade*/);
|
||||
|
||||
if (packageStats != null) {
|
||||
long endTime = System.currentTimeMillis();
|
||||
@@ -258,12 +264,12 @@ public class PackageDexOptimizer {
|
||||
* that seems wasteful.
|
||||
*/
|
||||
public int dexOptSecondaryDexPath(ApplicationInfo info, String path, Set<String> isas,
|
||||
String compilerFilter, boolean isUsedByOtherApps) {
|
||||
String compilerFilter, boolean isUsedByOtherApps, boolean downgrade) {
|
||||
synchronized (mInstallLock) {
|
||||
final long acquireTime = acquireWakeLockLI(info.uid);
|
||||
try {
|
||||
return dexOptSecondaryDexPathLI(info, path, isas, compilerFilter,
|
||||
isUsedByOtherApps);
|
||||
isUsedByOtherApps, downgrade);
|
||||
} finally {
|
||||
releaseWakeLockLI(acquireTime);
|
||||
}
|
||||
@@ -305,7 +311,7 @@ public class PackageDexOptimizer {
|
||||
|
||||
@GuardedBy("mInstallLock")
|
||||
private int dexOptSecondaryDexPathLI(ApplicationInfo info, String path, Set<String> isas,
|
||||
String compilerFilter, boolean isUsedByOtherApps) {
|
||||
String compilerFilter, boolean isUsedByOtherApps, boolean downgrade) {
|
||||
compilerFilter = getRealCompilerFilter(info, compilerFilter, isUsedByOtherApps);
|
||||
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
|
||||
// Secondary dex files are currently not compiled at boot.
|
||||
@@ -335,7 +341,8 @@ public class PackageDexOptimizer {
|
||||
// TODO(calin): maybe add a separate call.
|
||||
mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
|
||||
/*oatDir*/ null, dexoptFlags,
|
||||
compilerFilter, info.volumeUuid, SKIP_SHARED_LIBRARY_CHECK, info.seInfoUser);
|
||||
compilerFilter, info.volumeUuid, SKIP_SHARED_LIBRARY_CHECK, info.seInfoUser,
|
||||
downgrade);
|
||||
}
|
||||
|
||||
return DEX_OPT_PERFORMED;
|
||||
@@ -436,11 +443,11 @@ public class PackageDexOptimizer {
|
||||
* configuration (isa, compiler filter, profile).
|
||||
*/
|
||||
private int getDexoptNeeded(String path, String isa, String compilerFilter,
|
||||
boolean newProfile) {
|
||||
boolean newProfile, boolean downgrade) {
|
||||
int dexoptNeeded;
|
||||
try {
|
||||
dexoptNeeded = DexFile.getDexOptNeeded(path, isa, compilerFilter, newProfile,
|
||||
false /* downgrade */);
|
||||
dexoptNeeded = DexFile.getDexOptNeeded(path, isa, compilerFilter, newProfile,
|
||||
downgrade);
|
||||
} catch (IOException ioe) {
|
||||
Slog.w(TAG, "IOException reading apk: " + path, ioe);
|
||||
return DEX_OPT_FAILED;
|
||||
|
||||
@@ -280,6 +280,7 @@ import com.android.server.pm.PermissionsState.PermissionState;
|
||||
import com.android.server.pm.Settings.DatabaseVersion;
|
||||
import com.android.server.pm.Settings.VersionInfo;
|
||||
import com.android.server.pm.dex.DexManager;
|
||||
import com.android.server.pm.dex.PackageDexUsage;
|
||||
import com.android.server.storage.DeviceStorageMonitorInternal;
|
||||
|
||||
import dalvik.system.CloseGuard;
|
||||
@@ -559,8 +560,9 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
public static final int REASON_INSTALL = 2;
|
||||
public static final int REASON_BACKGROUND_DEXOPT = 3;
|
||||
public static final int REASON_AB_OTA = 4;
|
||||
public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 5;
|
||||
|
||||
public static final int REASON_LAST = REASON_AB_OTA;
|
||||
public static final int REASON_LAST = REASON_INACTIVE_PACKAGE_DOWNGRADE;
|
||||
|
||||
/** All dangerous permission names in the same order as the events in MetricsEvent */
|
||||
private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
|
||||
@@ -9396,7 +9398,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
false /* checkProfiles */,
|
||||
compilerFilter,
|
||||
false /* force */,
|
||||
bootComplete);
|
||||
bootComplete,
|
||||
false /* downgrade */);
|
||||
|
||||
boolean secondaryDexOptStatus = true;
|
||||
if (pkg.isSystemApp()) {
|
||||
@@ -9405,7 +9408,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
secondaryDexOptStatus = mDexManager.dexoptSecondaryDex(pkg.packageName,
|
||||
compilerFilter,
|
||||
false /* force */,
|
||||
true /* compileOnlySharedDex */);
|
||||
true /* compileOnlySharedDex */,
|
||||
false /* downgrade */);
|
||||
}
|
||||
|
||||
if (secondaryDexOptStatus) {
|
||||
@@ -9493,14 +9497,16 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
@Override
|
||||
public boolean performDexOpt(String packageName,
|
||||
boolean checkProfiles, int compileReason, boolean force, boolean bootComplete) {
|
||||
boolean checkProfiles, int compileReason, boolean force, boolean bootComplete,
|
||||
boolean downgrade) {
|
||||
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
|
||||
return false;
|
||||
} else if (isInstantApp(packageName, UserHandle.getCallingUserId())) {
|
||||
return false;
|
||||
}
|
||||
int dexoptStatus = performDexOptWithStatus(
|
||||
packageName, checkProfiles, compileReason, force, bootComplete);
|
||||
packageName, checkProfiles, compileReason, force, bootComplete,
|
||||
downgrade);
|
||||
return dexoptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
|
||||
}
|
||||
|
||||
@@ -9511,9 +9517,10 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
* {@link PackageDexOptimizer#DEX_OPT_FAILED}
|
||||
*/
|
||||
/* package */ int performDexOptWithStatus(String packageName,
|
||||
boolean checkProfiles, int compileReason, boolean force, boolean bootComplete) {
|
||||
boolean checkProfiles, int compileReason, boolean force, boolean bootComplete,
|
||||
boolean downgrade) {
|
||||
return performDexOptTraced(packageName, checkProfiles,
|
||||
getCompilerFilterForReason(compileReason), force, bootComplete);
|
||||
getCompilerFilterForReason(compileReason), force, bootComplete, downgrade);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -9526,17 +9533,17 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
return false;
|
||||
}
|
||||
int dexOptStatus = performDexOptTraced(packageName, checkProfiles,
|
||||
targetCompilerFilter, force, bootComplete);
|
||||
targetCompilerFilter, force, bootComplete, false /* downgrade */);
|
||||
return dexOptStatus != PackageDexOptimizer.DEX_OPT_FAILED;
|
||||
}
|
||||
|
||||
private int performDexOptTraced(String packageName,
|
||||
boolean checkProfiles, String targetCompilerFilter, boolean force,
|
||||
boolean bootComplete) {
|
||||
boolean bootComplete, boolean downgrade) {
|
||||
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
|
||||
try {
|
||||
return performDexOptInternal(packageName, checkProfiles,
|
||||
targetCompilerFilter, force, bootComplete);
|
||||
targetCompilerFilter, force, bootComplete, downgrade);
|
||||
} finally {
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
}
|
||||
@@ -9546,7 +9553,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
// if the package can now be considered up to date for the given filter.
|
||||
private int performDexOptInternal(String packageName,
|
||||
boolean checkProfiles, String targetCompilerFilter, boolean force,
|
||||
boolean bootComplete) {
|
||||
boolean bootComplete, boolean downgrade) {
|
||||
PackageParser.Package p;
|
||||
synchronized (mPackages) {
|
||||
p = mPackages.get(packageName);
|
||||
@@ -9561,7 +9568,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
try {
|
||||
synchronized (mInstallLock) {
|
||||
return performDexOptInternalWithDependenciesLI(p, checkProfiles,
|
||||
targetCompilerFilter, force, bootComplete);
|
||||
targetCompilerFilter, force, bootComplete, downgrade);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingId);
|
||||
@@ -9582,7 +9589,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
|
||||
private int performDexOptInternalWithDependenciesLI(PackageParser.Package p,
|
||||
boolean checkProfiles, String targetCompilerFilter,
|
||||
boolean force, boolean bootComplete) {
|
||||
boolean force, boolean bootComplete, boolean downgrade) {
|
||||
// Select the dex optimizer based on the force parameter.
|
||||
// Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to
|
||||
// allocate an object here.
|
||||
@@ -9607,12 +9614,13 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
targetCompilerFilter,
|
||||
getOrCreateCompilerPackageStats(depPackage),
|
||||
true /* isUsedByOtherApps */,
|
||||
bootComplete);
|
||||
bootComplete,
|
||||
downgrade);
|
||||
}
|
||||
}
|
||||
return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets, checkProfiles,
|
||||
targetCompilerFilter, getOrCreateCompilerPackageStats(p),
|
||||
mDexManager.isUsedByOtherApps(p.packageName), bootComplete);
|
||||
mDexManager.isUsedByOtherApps(p.packageName), bootComplete, downgrade);
|
||||
}
|
||||
|
||||
// Performs dexopt on the used secondary dex files belonging to the given package.
|
||||
@@ -9627,12 +9635,12 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
return false;
|
||||
}
|
||||
return mDexManager.dexoptSecondaryDex(packageName, compilerFilter, force,
|
||||
/* compileOnlySharedDex*/ false);
|
||||
false /* compileOnlySharedDex */, false /* downgrade */);
|
||||
}
|
||||
|
||||
public boolean performDexOptSecondary(String packageName, int compileReason,
|
||||
boolean force) {
|
||||
return mDexManager.dexoptSecondaryDex(packageName, compileReason, force);
|
||||
boolean force, boolean downgrade) {
|
||||
return mDexManager.dexoptSecondaryDex(packageName, compileReason, force, downgrade);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -9811,7 +9819,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
final int res = performDexOptInternalWithDependenciesLI(pkg,
|
||||
false /* checkProfiles */, getDefaultCompilerFilter(),
|
||||
true /* force */,
|
||||
true /* bootComplete */);
|
||||
true /* bootComplete */,
|
||||
false /* downgrade */);
|
||||
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
|
||||
@@ -16242,7 +16251,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
|
||||
void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
|
||||
if (!allCodePaths.isEmpty()) {
|
||||
if (instructionSets == null) {
|
||||
throw new IllegalStateException("instructionSet == null");
|
||||
@@ -18280,7 +18289,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
getCompilerFilterForReason(REASON_INSTALL),
|
||||
getOrCreateCompilerPackageStats(pkg),
|
||||
mDexManager.isUsedByOtherApps(pkg.packageName),
|
||||
true /* bootComplete */);
|
||||
true /* bootComplete */,
|
||||
false /* downgrade */);
|
||||
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
|
||||
}
|
||||
|
||||
@@ -25054,6 +25064,29 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
|
||||
Set<String> unusedPackages = new HashSet<>();
|
||||
long currentTimeInMillis = System.currentTimeMillis();
|
||||
synchronized (mPackages) {
|
||||
for (PackageParser.Package pkg : mPackages.values()) {
|
||||
PackageSetting ps = mSettings.mPackages.get(pkg.packageName);
|
||||
if (ps == null) {
|
||||
continue;
|
||||
}
|
||||
PackageDexUsage.PackageUseInfo packageUseInfo = getDexManager().getPackageUseInfo(
|
||||
pkg.packageName);
|
||||
if (PackageManagerServiceUtils
|
||||
.isUnusedSinceTimeInMillis(ps.firstInstallTime, currentTimeInMillis,
|
||||
downgradeTimeThresholdMillis, packageUseInfo,
|
||||
pkg.getLatestPackageUseTimeInMills(),
|
||||
pkg.getLatestForegroundPackageUseTimeInMills())) {
|
||||
unusedPackages.add(pkg.packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return unusedPackages;
|
||||
}
|
||||
}
|
||||
|
||||
interface PackageSender {
|
||||
|
||||
@@ -26,7 +26,7 @@ import dalvik.system.DexFile;
|
||||
public class PackageManagerServiceCompilerMapping {
|
||||
// Names for compilation reasons.
|
||||
static final String REASON_STRINGS[] = {
|
||||
"first-boot", "boot", "install", "bg-dexopt", "ab-ota"
|
||||
"first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive"
|
||||
};
|
||||
|
||||
// Static block to ensure the strings array is of the right length.
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package com.android.server.pm;
|
||||
|
||||
import com.android.server.pm.dex.DexManager;
|
||||
import com.android.server.pm.dex.PackageDexUsage;
|
||||
|
||||
import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
|
||||
import static com.android.server.pm.PackageManagerService.TAG;
|
||||
|
||||
@@ -24,6 +27,7 @@ import com.android.internal.util.ArrayUtils;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.AppGlobals;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Build;
|
||||
@@ -185,6 +189,41 @@ public class PackageManagerServiceUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the package was inactive during since <code>thresholdTimeinMillis</code>.
|
||||
* Package is considered active, if:
|
||||
* 1) It was active in foreground.
|
||||
* 2) It was active in background and also used by other apps.
|
||||
*
|
||||
* If it doesn't have sufficient information about the package, it return <code>false</code>.
|
||||
*/
|
||||
static boolean isUnusedSinceTimeInMillis(long firstInstallTime, long currentTimeInMillis,
|
||||
long thresholdTimeinMillis, PackageDexUsage.PackageUseInfo packageUseInfo,
|
||||
long latestPackageUseTimeInMillis, long latestForegroundPackageUseTimeInMillis) {
|
||||
|
||||
if (currentTimeInMillis - firstInstallTime < thresholdTimeinMillis) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the app was active in foreground during the threshold period.
|
||||
boolean isActiveInForeground = (currentTimeInMillis
|
||||
- latestForegroundPackageUseTimeInMillis)
|
||||
< thresholdTimeinMillis;
|
||||
|
||||
if (isActiveInForeground) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the app was active in background during the threshold period and was used
|
||||
// by other packages.
|
||||
boolean isActiveInBackgroundAndUsedByOtherPackages = ((currentTimeInMillis
|
||||
- latestPackageUseTimeInMillis)
|
||||
< thresholdTimeinMillis)
|
||||
&& packageUseInfo.isUsedByOtherApps();
|
||||
|
||||
return !isActiveInBackgroundAndUsedByOtherPackages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the canonicalized path of {@code path} as per {@code realpath(3)}
|
||||
* semantics.
|
||||
|
||||
@@ -304,10 +304,11 @@ public class DexManager {
|
||||
* @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, int compilerReason, boolean force) {
|
||||
public boolean dexoptSecondaryDex(String packageName, int compilerReason, boolean force,
|
||||
boolean downgrade) {
|
||||
return dexoptSecondaryDex(packageName,
|
||||
PackageManagerServiceCompilerMapping.getCompilerFilterForReason(compilerReason),
|
||||
force, /* compileOnlySharedDex */ false);
|
||||
force, /* compileOnlySharedDex */ false, downgrade);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,7 +317,7 @@ public class DexManager {
|
||||
* because they don't need to be compiled)..
|
||||
*/
|
||||
public boolean dexoptSecondaryDex(String packageName, String compilerFilter, boolean force,
|
||||
boolean compileOnlySharedDex) {
|
||||
boolean compileOnlySharedDex, boolean downgrade) {
|
||||
// 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
|
||||
@@ -360,7 +361,8 @@ public class DexManager {
|
||||
}
|
||||
|
||||
int result = pdo.dexOptSecondaryDexPath(pkg.applicationInfo, dexPath,
|
||||
dexUseInfo.getLoaderIsas(), compilerFilter, dexUseInfo.isUsedByOtherApps());
|
||||
dexUseInfo.getLoaderIsas(), compilerFilter, dexUseInfo.isUsedByOtherApps(),
|
||||
downgrade);
|
||||
success = success && (result != PackageDexOptimizer.DEX_OPT_FAILED);
|
||||
}
|
||||
return success;
|
||||
@@ -476,7 +478,7 @@ public class DexManager {
|
||||
String compilerFilter = PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
|
||||
PackageManagerService.REASON_INSTALL);
|
||||
int result = mPackageDexOptimizer.dexOptSecondaryDexPath(info, dexPath, isas,
|
||||
compilerFilter, isUsedByOtherApps);
|
||||
compilerFilter, isUsedByOtherApps, /* downgrade */ false);
|
||||
|
||||
// If we fail to optimize the package log an error but don't propagate the error
|
||||
// back to the app. The app cannot do much about it and the background job
|
||||
|
||||
Reference in New Issue
Block a user