Loading services/core/java/com/android/server/pm/dex/PackageDexUsage.java +20 −8 Original line number Diff line number Diff line Loading @@ -16,9 +16,9 @@ package com.android.server.pm.dex; import android.os.Build; import android.util.AtomicFile; import android.util.Slog; import android.os.Build; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading @@ -26,26 +26,27 @@ import com.android.internal.util.FastPrintWriter; import com.android.server.pm.AbstractStatsBase; import com.android.server.pm.PackageManagerServiceUtils; import dalvik.system.VMRuntime; import libcore.io.IoUtils; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.util.Collections; import java.util.Iterator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Objects; import java.util.Set; import dalvik.system.VMRuntime; import libcore.io.IoUtils; /** * Stat file which store usage information about dex files. */ Loading Loading @@ -86,6 +87,13 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { private static final String UNSUPPORTED_CLASS_LOADER_CONTEXT = "=UnsupportedClassLoaderContext="; /** * Limit on how many secondary DEX paths we store for a single owner, to avoid one app causing * unbounded memory consumption. */ @VisibleForTesting /* package */ static final int MAX_SECONDARY_FILES_PER_OWNER = 100; // Map which structures the information we have on a package. // Maps package name to package data (which stores info about UsedByOtherApps and // secondary dex files.). Loading Loading @@ -164,8 +172,12 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { DexUseInfo existingData = packageUseInfo.mDexUseInfoMap.get(dexPath); if (existingData == null) { // It's the first time we see this dex file. if (packageUseInfo.mDexUseInfoMap.size() < MAX_SECONDARY_FILES_PER_OWNER) { packageUseInfo.mDexUseInfoMap.put(dexPath, newData); return true; } else { return updateLoadingPackages; } } else { if (ownerUserId != existingData.mOwnerUserId) { // Oups, this should never happen, the DexManager who calls this should Loading services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java +44 −15 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.pm.dex; import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; import static com.android.server.pm.dex.PackageDexUsage.MAX_SECONDARY_FILES_PER_OWNER; import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo; import static org.junit.Assert.assertEquals; Loading @@ -31,24 +32,28 @@ import android.os.Build; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import dalvik.system.VMRuntime; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import dalvik.system.VMRuntime; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @RunWith(AndroidJUnit4.class) @SmallTest public class PackageDexUsageTests { private static final String ISA = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); private PackageDexUsage mPackageDexUsage; private TestData mFooBaseUser0; Loading @@ -71,25 +76,23 @@ public class PackageDexUsageTests { String fooCodeDir = "/data/app/com.google.foo/"; String fooDataDir = "/data/user/0/com.google.foo/"; String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); mFooBaseUser0 = new TestData(fooPackageName, fooCodeDir + "base.apk", 0, isa, false, true, fooPackageName); fooCodeDir + "base.apk", 0, ISA, false, true, fooPackageName); mFooSplit1User0 = new TestData(fooPackageName, fooCodeDir + "split-1.apk", 0, isa, false, true, fooPackageName); fooCodeDir + "split-1.apk", 0, ISA, false, true, fooPackageName); mFooSplit2UsedByOtherApps0 = new TestData(fooPackageName, fooCodeDir + "split-2.apk", 0, isa, true, true, "used.by.other.com"); fooCodeDir + "split-2.apk", 0, ISA, true, true, "used.by.other.com"); mFooSecondary1User0 = new TestData(fooPackageName, fooDataDir + "sec-1.dex", 0, isa, false, false, fooPackageName); fooDataDir + "sec-1.dex", 0, ISA, false, false, fooPackageName); mFooSecondary1User1 = new TestData(fooPackageName, fooDataDir + "sec-1.dex", 1, isa, false, false, fooPackageName); fooDataDir + "sec-1.dex", 1, ISA, false, false, fooPackageName); mFooSecondary2UsedByOtherApps0 = new TestData(fooPackageName, fooDataDir + "sec-2.dex", 0, isa, true, false, "used.by.other.com"); fooDataDir + "sec-2.dex", 0, ISA, true, false, "used.by.other.com"); mInvalidIsa = new TestData(fooPackageName, fooCodeDir + "base.apk", 0, "INVALID_ISA", false, true, "INALID_USER"); Loading @@ -100,11 +103,11 @@ public class PackageDexUsageTests { String barDataDir1 = "/data/user/1/com.google.bar/"; mBarBaseUser0 = new TestData(barPackageName, barCodeDir + "base.apk", 0, isa, false, true, barPackageName); barCodeDir + "base.apk", 0, ISA, false, true, barPackageName); mBarSecondary1User0 = new TestData(barPackageName, barDataDir + "sec-1.dex", 0, isa, false, false, barPackageName); barDataDir + "sec-1.dex", 0, ISA, false, false, barPackageName); mBarSecondary2User1 = new TestData(barPackageName, barDataDir1 + "sec-2.dex", 1, isa, false, false, barPackageName); barDataDir1 + "sec-2.dex", 1, ISA, false, false, barPackageName); } @Test Loading Loading @@ -182,6 +185,25 @@ public class PackageDexUsageTests { mFooSplit2UsedByOtherApps0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0); } @Test public void testRecordTooManySecondaries() { int tooManyFiles = MAX_SECONDARY_FILES_PER_OWNER + 1; List<TestData> expectedSecondaries = new ArrayList<>(); for (int i = 1; i <= tooManyFiles; i++) { String fooPackageName = "com.google.foo"; TestData testData = new TestData(fooPackageName, "/data/user/0/" + fooPackageName + "/sec-" + i + "1.dex", 0, ISA, false, false, fooPackageName); if (i < tooManyFiles) { assertTrue("Adding " + testData.mDexFile, record(testData)); expectedSecondaries.add(testData); } else { assertFalse("Adding " + testData.mDexFile, record(testData)); } assertPackageDexUsage(mPackageDexUsage, null, null, expectedSecondaries); } } @Test public void testMultiplePackages() { assertTrue(record(mFooBaseUser0)); Loading Loading @@ -540,7 +562,14 @@ public class PackageDexUsageTests { private void assertPackageDexUsage(PackageDexUsage packageDexUsage, Set<String> users, TestData primary, TestData... secondaries) { String packageName = primary == null ? secondaries[0].mPackageName : primary.mPackageName; assertPackageDexUsage(packageDexUsage, users, primary, Arrays.asList(secondaries)); } private void assertPackageDexUsage(PackageDexUsage packageDexUsage, Set<String> users, TestData primary, List<TestData> secondaries) { String packageName = primary == null ? secondaries.get(0).mPackageName : primary.mPackageName; boolean primaryUsedByOtherApps = primary != null && primary.mUsedByOtherApps; PackageUseInfo pInfo = packageDexUsage.getPackageUseInfo(packageName); Loading @@ -554,7 +583,7 @@ public class PackageDexUsageTests { } Map<String, DexUseInfo> dexUseInfoMap = pInfo.getDexUseInfoMap(); assertEquals(secondaries.length, dexUseInfoMap.size()); assertEquals(secondaries.size(), dexUseInfoMap.size()); // Check dex use info for (TestData testData : secondaries) { Loading Loading
services/core/java/com/android/server/pm/dex/PackageDexUsage.java +20 −8 Original line number Diff line number Diff line Loading @@ -16,9 +16,9 @@ package com.android.server.pm.dex; import android.os.Build; import android.util.AtomicFile; import android.util.Slog; import android.os.Build; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; Loading @@ -26,26 +26,27 @@ import com.android.internal.util.FastPrintWriter; import com.android.server.pm.AbstractStatsBase; import com.android.server.pm.PackageManagerServiceUtils; import dalvik.system.VMRuntime; import libcore.io.IoUtils; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.util.Collections; import java.util.Iterator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Objects; import java.util.Set; import dalvik.system.VMRuntime; import libcore.io.IoUtils; /** * Stat file which store usage information about dex files. */ Loading Loading @@ -86,6 +87,13 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { private static final String UNSUPPORTED_CLASS_LOADER_CONTEXT = "=UnsupportedClassLoaderContext="; /** * Limit on how many secondary DEX paths we store for a single owner, to avoid one app causing * unbounded memory consumption. */ @VisibleForTesting /* package */ static final int MAX_SECONDARY_FILES_PER_OWNER = 100; // Map which structures the information we have on a package. // Maps package name to package data (which stores info about UsedByOtherApps and // secondary dex files.). Loading Loading @@ -164,8 +172,12 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { DexUseInfo existingData = packageUseInfo.mDexUseInfoMap.get(dexPath); if (existingData == null) { // It's the first time we see this dex file. if (packageUseInfo.mDexUseInfoMap.size() < MAX_SECONDARY_FILES_PER_OWNER) { packageUseInfo.mDexUseInfoMap.put(dexPath, newData); return true; } else { return updateLoadingPackages; } } else { if (ownerUserId != existingData.mOwnerUserId) { // Oups, this should never happen, the DexManager who calls this should Loading
services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java +44 −15 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.pm.dex; import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; import static com.android.server.pm.dex.PackageDexUsage.MAX_SECONDARY_FILES_PER_OWNER; import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo; import static org.junit.Assert.assertEquals; Loading @@ -31,24 +32,28 @@ import android.os.Build; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import dalvik.system.VMRuntime; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import dalvik.system.VMRuntime; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @RunWith(AndroidJUnit4.class) @SmallTest public class PackageDexUsageTests { private static final String ISA = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); private PackageDexUsage mPackageDexUsage; private TestData mFooBaseUser0; Loading @@ -71,25 +76,23 @@ public class PackageDexUsageTests { String fooCodeDir = "/data/app/com.google.foo/"; String fooDataDir = "/data/user/0/com.google.foo/"; String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); mFooBaseUser0 = new TestData(fooPackageName, fooCodeDir + "base.apk", 0, isa, false, true, fooPackageName); fooCodeDir + "base.apk", 0, ISA, false, true, fooPackageName); mFooSplit1User0 = new TestData(fooPackageName, fooCodeDir + "split-1.apk", 0, isa, false, true, fooPackageName); fooCodeDir + "split-1.apk", 0, ISA, false, true, fooPackageName); mFooSplit2UsedByOtherApps0 = new TestData(fooPackageName, fooCodeDir + "split-2.apk", 0, isa, true, true, "used.by.other.com"); fooCodeDir + "split-2.apk", 0, ISA, true, true, "used.by.other.com"); mFooSecondary1User0 = new TestData(fooPackageName, fooDataDir + "sec-1.dex", 0, isa, false, false, fooPackageName); fooDataDir + "sec-1.dex", 0, ISA, false, false, fooPackageName); mFooSecondary1User1 = new TestData(fooPackageName, fooDataDir + "sec-1.dex", 1, isa, false, false, fooPackageName); fooDataDir + "sec-1.dex", 1, ISA, false, false, fooPackageName); mFooSecondary2UsedByOtherApps0 = new TestData(fooPackageName, fooDataDir + "sec-2.dex", 0, isa, true, false, "used.by.other.com"); fooDataDir + "sec-2.dex", 0, ISA, true, false, "used.by.other.com"); mInvalidIsa = new TestData(fooPackageName, fooCodeDir + "base.apk", 0, "INVALID_ISA", false, true, "INALID_USER"); Loading @@ -100,11 +103,11 @@ public class PackageDexUsageTests { String barDataDir1 = "/data/user/1/com.google.bar/"; mBarBaseUser0 = new TestData(barPackageName, barCodeDir + "base.apk", 0, isa, false, true, barPackageName); barCodeDir + "base.apk", 0, ISA, false, true, barPackageName); mBarSecondary1User0 = new TestData(barPackageName, barDataDir + "sec-1.dex", 0, isa, false, false, barPackageName); barDataDir + "sec-1.dex", 0, ISA, false, false, barPackageName); mBarSecondary2User1 = new TestData(barPackageName, barDataDir1 + "sec-2.dex", 1, isa, false, false, barPackageName); barDataDir1 + "sec-2.dex", 1, ISA, false, false, barPackageName); } @Test Loading Loading @@ -182,6 +185,25 @@ public class PackageDexUsageTests { mFooSplit2UsedByOtherApps0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0); } @Test public void testRecordTooManySecondaries() { int tooManyFiles = MAX_SECONDARY_FILES_PER_OWNER + 1; List<TestData> expectedSecondaries = new ArrayList<>(); for (int i = 1; i <= tooManyFiles; i++) { String fooPackageName = "com.google.foo"; TestData testData = new TestData(fooPackageName, "/data/user/0/" + fooPackageName + "/sec-" + i + "1.dex", 0, ISA, false, false, fooPackageName); if (i < tooManyFiles) { assertTrue("Adding " + testData.mDexFile, record(testData)); expectedSecondaries.add(testData); } else { assertFalse("Adding " + testData.mDexFile, record(testData)); } assertPackageDexUsage(mPackageDexUsage, null, null, expectedSecondaries); } } @Test public void testMultiplePackages() { assertTrue(record(mFooBaseUser0)); Loading Loading @@ -540,7 +562,14 @@ public class PackageDexUsageTests { private void assertPackageDexUsage(PackageDexUsage packageDexUsage, Set<String> users, TestData primary, TestData... secondaries) { String packageName = primary == null ? secondaries[0].mPackageName : primary.mPackageName; assertPackageDexUsage(packageDexUsage, users, primary, Arrays.asList(secondaries)); } private void assertPackageDexUsage(PackageDexUsage packageDexUsage, Set<String> users, TestData primary, List<TestData> secondaries) { String packageName = primary == null ? secondaries.get(0).mPackageName : primary.mPackageName; boolean primaryUsedByOtherApps = primary != null && primary.mUsedByOtherApps; PackageUseInfo pInfo = packageDexUsage.getPackageUseInfo(packageName); Loading @@ -554,7 +583,7 @@ public class PackageDexUsageTests { } Map<String, DexUseInfo> dexUseInfoMap = pInfo.getDexUseInfoMap(); assertEquals(secondaries.length, dexUseInfoMap.size()); assertEquals(secondaries.size(), dexUseInfoMap.size()); // Check dex use info for (TestData testData : secondaries) { Loading