OtaDexopt: Downgrade apps when low on space

am: 1920d7b434

Change-Id: I8c2a5e7effd79109633976c9d8db04e0d25eaf2c
This commit is contained in:
Andreas Gampe
2016-09-29 00:18:13 +00:00
committed by android-build-merger
2 changed files with 70 additions and 25 deletions

View File

@@ -53,6 +53,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
// The synthetic library dependencies denoting "no checks." // The synthetic library dependencies denoting "no checks."
private final static String[] NO_LIBRARIES = new String[] { "&" }; private final static String[] NO_LIBRARIES = new String[] { "&" };
// The amount of "available" (free - low threshold) space necessary at the start of an OTA to
// not bulk-delete unused apps' odex files.
private final static long BULK_DELETE_THRESHOLD = 1024 * 1024 * 1024; // 1GB.
private final Context mContext; private final Context mContext;
private final PackageManagerService mPackageManagerService; private final PackageManagerService mPackageManagerService;
@@ -128,6 +132,14 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT)); generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT));
} }
completeSize = mDexoptCommands.size(); completeSize = mDexoptCommands.size();
if (getAvailableSpace() < BULK_DELETE_THRESHOLD) {
Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
+ PackageManagerServiceUtils.packagesToString(others));
for (PackageParser.Package pkg : others) {
deleteOatArtifactsOfPackage(pkg);
}
}
} }
@Override @Override
@@ -169,28 +181,65 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
String next = mDexoptCommands.remove(0); String next = mDexoptCommands.remove(0);
if (IsFreeSpaceAvailable()) { if (getAvailableSpace() > 0) {
return next; return next;
} else { } else {
if (DEBUG_DEXOPT) {
Log.w(TAG, "Not enough space for OTA dexopt, stopping with "
+ (mDexoptCommands.size() + 1) + " commands left.");
}
mDexoptCommands.clear(); mDexoptCommands.clear();
return "(no free space)"; return "(no free space)";
} }
} }
/** private long getMainLowSpaceThreshold() {
* Check for low space. Returns true if there's space left.
*/
private boolean IsFreeSpaceAvailable() {
// TODO: If apps are not installed in the internal /data partition, we should compare
// against that storage's free capacity.
File dataDir = Environment.getDataDirectory(); File dataDir = Environment.getDataDirectory();
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir); long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir);
if (lowThreshold == 0) { if (lowThreshold == 0) {
throw new IllegalStateException("Invalid low memory threshold"); throw new IllegalStateException("Invalid low memory threshold");
} }
return lowThreshold;
}
/**
* Returns the difference of free space to the low-storage-space threshold. Positive values
* indicate free bytes.
*/
private long getAvailableSpace() {
// TODO: If apps are not installed in the internal /data partition, we should compare
// against that storage's free capacity.
long lowThreshold = getMainLowSpaceThreshold();
File dataDir = Environment.getDataDirectory();
long usableSpace = dataDir.getUsableSpace(); long usableSpace = dataDir.getUsableSpace();
return (usableSpace >= lowThreshold);
return usableSpace - lowThreshold;
}
private static String getOatDir(PackageParser.Package pkg) {
if (!pkg.canHaveOatDir()) {
return null;
}
File codePath = new File(pkg.codePath);
if (codePath.isDirectory()) {
return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath();
}
return null;
}
private void deleteOatArtifactsOfPackage(PackageParser.Package pkg) {
String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
for (String codePath : pkg.getAllCodePaths()) {
for (String isa : instructionSets) {
try {
mPackageManagerService.mInstaller.deleteOdex(codePath, isa, getOatDir(pkg));
} catch (InstallerException e) {
Log.e(TAG, "Failed deleting oat files for " + codePath, e);
}
}
}
} }
/** /**

View File

@@ -168,23 +168,8 @@ public class PackageManagerServiceUtils {
packageManagerService); packageManagerService);
if (DEBUG_DEXOPT) { if (DEBUG_DEXOPT) {
StringBuilder sb = new StringBuilder(); Log.i(TAG, "Packages to be dexopted: " + packagesToString(result));
for (PackageParser.Package pkg : result) { Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs));
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(pkg.packageName);
}
Log.i(TAG, "Packages to be dexopted: " + sb.toString());
sb.setLength(0);
for (PackageParser.Package pkg : remainingPkgs) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(pkg.packageName);
}
Log.i(TAG, "Packages skipped from dexopt: " + sb.toString());
} }
return result; return result;
@@ -201,4 +186,15 @@ public class PackageManagerServiceUtils {
throw ee.rethrowAsIOException(); throw ee.rethrowAsIOException();
} }
} }
public static String packagesToString(Collection<PackageParser.Package> c) {
StringBuilder sb = new StringBuilder();
for (PackageParser.Package pkg : c) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(pkg.packageName);
}
return sb.toString();
}
} }