Allow non-user packages to be kept in the use data list
By default, we clean up the data from the package-dex-use.list at every boot. The clean up will remove any obsolete or uninstalled packages. Since system server will not show up as a regular app, we need to add a mechanism to ensure that its dex files are not cleaned up. Test: atest DexManagerTests PackageManagerTests Bug: 148774920 Change-Id: I0788163b066af5713b8763f1875338add2d49aa9
This commit is contained in:
@@ -45,6 +45,7 @@ import dalvik.system.VMRuntime;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -353,7 +354,9 @@ public class DexManager {
|
||||
|
||||
try {
|
||||
mPackageDexUsage.read();
|
||||
mPackageDexUsage.syncData(packageToUsersMap, packageToCodePaths);
|
||||
List<String> packagesToKeepDataAbout = new ArrayList<>();
|
||||
mPackageDexUsage.syncData(
|
||||
packageToUsersMap, packageToCodePaths, packagesToKeepDataAbout);
|
||||
} catch (Exception e) {
|
||||
mPackageDexUsage.clear();
|
||||
Slog.w(TAG, "Exception while loading package dex usage. "
|
||||
|
||||
@@ -474,13 +474,19 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
* Syncs the existing data with the set of available packages by removing obsolete entries.
|
||||
*/
|
||||
/*package*/ void syncData(Map<String, Set<Integer>> packageToUsersMap,
|
||||
Map<String, Set<String>> packageToCodePaths) {
|
||||
Map<String, Set<String>> packageToCodePaths,
|
||||
List<String> packagesToKeepDataAbout) {
|
||||
synchronized (mPackageUseInfoMap) {
|
||||
Iterator<Map.Entry<String, PackageUseInfo>> pIt =
|
||||
mPackageUseInfoMap.entrySet().iterator();
|
||||
while (pIt.hasNext()) {
|
||||
Map.Entry<String, PackageUseInfo> pEntry = pIt.next();
|
||||
String packageName = pEntry.getKey();
|
||||
if (packagesToKeepDataAbout.contains(packageName)) {
|
||||
// This is a package for which we should keep the data even if it's not
|
||||
// in the list of user packages.
|
||||
continue;
|
||||
}
|
||||
PackageUseInfo packageUseInfo = pEntry.getValue();
|
||||
Set<Integer> users = packageToUsersMap.get(packageName);
|
||||
if (users == null) {
|
||||
@@ -501,11 +507,27 @@ public class PackageDexUsage extends AbstractStatsBase<Void> {
|
||||
|
||||
// Sync the code paths.
|
||||
Set<String> codePaths = packageToCodePaths.get(packageName);
|
||||
Iterator<Map.Entry<String, Set<String>>> codeIt =
|
||||
|
||||
Iterator<Map.Entry<String, Set<String>>> recordedIt =
|
||||
packageUseInfo.mPrimaryCodePaths.entrySet().iterator();
|
||||
while (codeIt.hasNext()) {
|
||||
if (!codePaths.contains(codeIt.next().getKey())) {
|
||||
codeIt.remove();
|
||||
while (recordedIt.hasNext()) {
|
||||
Map.Entry<String, Set<String>> entry = recordedIt.next();
|
||||
String recordedCodePath = entry.getKey();
|
||||
if (!codePaths.contains(recordedCodePath)) {
|
||||
// Clean up a non existing code path.
|
||||
recordedIt.remove();
|
||||
} else {
|
||||
// Clean up a non existing loading package.
|
||||
Set<String> recordedLoadingPackages = entry.getValue();
|
||||
Iterator<String> recordedLoadingPackagesIt =
|
||||
recordedLoadingPackages.iterator();
|
||||
while (recordedLoadingPackagesIt.hasNext()) {
|
||||
String recordedLoadingPackage = recordedLoadingPackagesIt.next();
|
||||
if (!packagesToKeepDataAbout.contains(recordedLoadingPackage)
|
||||
&& !packageToUsersMap.containsKey(recordedLoadingPackage)) {
|
||||
recordedLoadingPackagesIt.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -282,13 +282,48 @@ public class PackageDexUsageTests {
|
||||
Map<String, Set<String>> packageToCodePaths = new HashMap<>();
|
||||
packageToCodePaths.put(mBarBaseUser0.mPackageName,
|
||||
new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile)));
|
||||
mPackageDexUsage.syncData(packageToUsersMap, packageToCodePaths);
|
||||
mPackageDexUsage.syncData(packageToUsersMap, packageToCodePaths, new ArrayList<String>());
|
||||
|
||||
// Assert that only user 1 files are there.
|
||||
assertPackageDexUsage(mBarBaseUser0, mBarSecondary2User1);
|
||||
assertNull(mPackageDexUsage.getPackageUseInfo(mFooBaseUser0.mPackageName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSyncDataKeepPackages() {
|
||||
PackageDexUsage packageDexUsage = new PackageDexUsage();
|
||||
// Write the record we want to keep and which won't be keep by default.
|
||||
Set<String> fooUsers = new HashSet<>(Arrays.asList(
|
||||
new String[] {mFooBaseUser0.mPackageName}));
|
||||
assertTrue(record(packageDexUsage, mFooBaseUser0, fooUsers));
|
||||
// Write a record that would be kept by default.
|
||||
Set<String> barUsers = new HashSet<>(Arrays.asList(
|
||||
new String[] {"another.package", mFooBaseUser0.mPackageName}));
|
||||
assertTrue(record(packageDexUsage, mBarBaseUser0, barUsers));
|
||||
|
||||
// Construct the user packages and their code paths (things that will be
|
||||
// kept by default during sync).
|
||||
Map<String, Set<Integer>> packageToUsersMap = new HashMap<>();
|
||||
packageToUsersMap.put(mBarBaseUser0.mPackageName,
|
||||
new HashSet<>(Arrays.asList(mBarBaseUser0.mOwnerUserId)));
|
||||
Map<String, Set<String>> packageToCodePaths = new HashMap<>();
|
||||
packageToCodePaths.put(mBarBaseUser0.mPackageName,
|
||||
new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile)));
|
||||
|
||||
// Sync data.
|
||||
List<String> keepData = new ArrayList<String>();
|
||||
keepData.add(mFooBaseUser0.mPackageName);
|
||||
packageDexUsage.syncData(packageToUsersMap, packageToCodePaths, keepData);
|
||||
|
||||
// Assert that both packages are kept
|
||||
assertPackageDexUsage(packageDexUsage, fooUsers, mFooBaseUser0);
|
||||
// "another.package" should not be in the loading packages after sync.
|
||||
Set<String> expectedBarUsers = new HashSet<>(Arrays.asList(
|
||||
new String[] {mFooBaseUser0.mPackageName}));
|
||||
assertPackageDexUsage(packageDexUsage, expectedBarUsers,
|
||||
mBarBaseUser0.updateUsedBy(mFooBaseUser0.mPackageName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemovePackage() {
|
||||
// Record Bar secondaries for two different users.
|
||||
@@ -501,7 +536,7 @@ public class PackageDexUsageTests {
|
||||
new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mOwnerUserId)));
|
||||
|
||||
// Sync the data.
|
||||
packageDexUsage.syncData(packageToUsersMap, packageToCodePaths);
|
||||
packageDexUsage.syncData(packageToUsersMap, packageToCodePaths, new ArrayList<>());
|
||||
|
||||
// Assert foo code paths.
|
||||
assertPackageDexUsage(
|
||||
@@ -654,9 +689,9 @@ public class PackageDexUsageTests {
|
||||
mPrimaryOrSplit, mUsedBy, newContext);
|
||||
}
|
||||
|
||||
private TestData updateUseByOthers(boolean newUsedByOthers) {
|
||||
private TestData updateUsedBy(String newUsedBy) {
|
||||
return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa,
|
||||
mPrimaryOrSplit, mUsedBy, mClassLoaderContext);
|
||||
mPrimaryOrSplit, newUsedBy, mClassLoaderContext);
|
||||
}
|
||||
|
||||
private boolean isUsedByOtherApps() {
|
||||
|
||||
Reference in New Issue
Block a user