DexManagerTests.java revision c22c30ed1c05c5c24185dc4d380d1c5026923d46
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17package com.android.server.pm.dex; 18 19import android.os.Build; 20import android.content.pm.ApplicationInfo; 21import android.content.pm.PackageInfo; 22import android.support.test.filters.SmallTest; 23import android.support.test.runner.AndroidJUnit4; 24 25import dalvik.system.VMRuntime; 26 27import java.util.ArrayList; 28import java.util.Arrays; 29import java.util.HashMap; 30import java.util.List; 31import java.util.Map; 32 33import org.junit.Before; 34import org.junit.Test; 35import org.junit.runner.RunWith; 36 37import static org.junit.Assert.assertEquals; 38import static org.junit.Assert.assertFalse; 39import static org.junit.Assert.assertNotNull; 40import static org.junit.Assert.assertNull; 41import static org.junit.Assert.assertTrue; 42import static org.junit.Assert.fail; 43 44import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo; 45import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; 46 47@RunWith(AndroidJUnit4.class) 48@SmallTest 49public class DexManagerTests { 50 private DexManager mDexManager; 51 52 private TestData mFooUser0; 53 private TestData mBarUser0; 54 private TestData mBarUser1; 55 private TestData mInvalidIsa; 56 private TestData mDoesNotExist; 57 58 private int mUser0; 59 private int mUser1; 60 @Before 61 public void setup() { 62 63 mUser0 = 0; 64 mUser1 = 1; 65 66 String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); 67 String foo = "foo"; 68 String bar = "bar"; 69 70 mFooUser0 = new TestData(foo, isa, mUser0); 71 mBarUser0 = new TestData(bar, isa, mUser0); 72 mBarUser1 = new TestData(bar, isa, mUser1); 73 mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0); 74 mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1); 75 76 mDexManager = new DexManager(null, null); 77 78 // Foo and Bar are available to user0. 79 // Only Bar is available to user1; 80 Map<Integer, List<PackageInfo>> existingPackages = new HashMap<>(); 81 existingPackages.put(mUser0, Arrays.asList(mFooUser0.mPackageInfo, mBarUser0.mPackageInfo)); 82 existingPackages.put(mUser1, Arrays.asList(mBarUser1.mPackageInfo)); 83 mDexManager.load(existingPackages); 84 } 85 86 @Test 87 public void testNotifyPrimaryUse() { 88 // The main dex file and splits are re-loaded by the app. 89 notifyDexLoad(mFooUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); 90 91 // Package is not used by others, so we should get nothing back. 92 assertNull(getPackageUseInfo(mFooUser0)); 93 } 94 95 @Test 96 public void testNotifyPrimaryForeignUse() { 97 // Foo loads Bar main apks. 98 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 99 100 // Bar is used by others now and should be in our records 101 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 102 assertNotNull(pui); 103 assertTrue(pui.isUsedByOtherApps()); 104 assertTrue(pui.getDexUseInfoMap().isEmpty()); 105 } 106 107 @Test 108 public void testNotifySecondary() { 109 // Foo loads its own secondary files. 110 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 111 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 112 113 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 114 assertNotNull(pui); 115 assertFalse(pui.isUsedByOtherApps()); 116 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 117 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 118 } 119 120 @Test 121 public void testNotifySecondaryForeign() { 122 // Foo loads bar secondary files. 123 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 124 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 125 126 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 127 assertNotNull(pui); 128 assertFalse(pui.isUsedByOtherApps()); 129 assertEquals(barSecondaries.size(), pui.getDexUseInfoMap().size()); 130 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 131 } 132 133 @Test 134 public void testNotifySequence() { 135 // Foo loads its own secondary files. 136 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 137 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 138 // Foo loads Bar own secondary files. 139 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 140 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 141 // Foo loads Bar primary files. 142 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 143 // Bar loads its own secondary files. 144 notifyDexLoad(mBarUser0, barSecondaries, mUser0); 145 // Bar loads some own secondary files which foo didn't load. 146 List<String> barSecondariesForOwnUse = mBarUser0.getSecondaryDexPathsForOwnUse(); 147 notifyDexLoad(mBarUser0, barSecondariesForOwnUse, mUser0); 148 149 // Check bar usage. Should be used by other app (for primary and barSecondaries). 150 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 151 assertNotNull(pui); 152 assertTrue(pui.isUsedByOtherApps()); 153 assertEquals(barSecondaries.size() + barSecondariesForOwnUse.size(), 154 pui.getDexUseInfoMap().size()); 155 156 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 157 assertSecondaryUse(mFooUser0, pui, barSecondariesForOwnUse, 158 /*isUsedByOtherApps*/false, mUser0); 159 160 // Check foo usage. Should not be used by other app. 161 pui = getPackageUseInfo(mFooUser0); 162 assertNotNull(pui); 163 assertFalse(pui.isUsedByOtherApps()); 164 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 165 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 166 } 167 168 @Test 169 public void testPackageUseInfoNotFound() { 170 // Assert we don't get back data we did not previously record. 171 assertNull(getPackageUseInfo(mFooUser0)); 172 } 173 174 @Test 175 public void testInvalidIsa() { 176 // Notifying with an invalid ISA should be ignored. 177 notifyDexLoad(mInvalidIsa, mInvalidIsa.getSecondaryDexPaths(), mUser0); 178 assertNull(getPackageUseInfo(mInvalidIsa)); 179 } 180 181 @Test 182 public void testNotExistingPackate() { 183 // Notifying about the load of a package which was previously not 184 // register in DexManager#load should be ignored. 185 notifyDexLoad(mDoesNotExist, mDoesNotExist.getBaseAndSplitDexPaths(), mUser0); 186 assertNull(getPackageUseInfo(mDoesNotExist)); 187 } 188 189 @Test 190 public void testCrossUserAttempt() { 191 // Bar from User1 tries to load secondary dex files from User0 Bar. 192 // Request should be ignored. 193 notifyDexLoad(mBarUser1, mBarUser0.getSecondaryDexPaths(), mUser1); 194 assertNull(getPackageUseInfo(mBarUser1)); 195 } 196 197 @Test 198 public void testPackageNotInstalledForUser() { 199 // User1 tries to load Foo which is installed for User0 but not for User1. 200 // Note that the PackageManagerService already filters this out but we 201 // still check that nothing goes unexpected in DexManager. 202 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser1); 203 assertNull(getPackageUseInfo(mBarUser1)); 204 } 205 206 private void assertSecondaryUse(TestData testData, PackageUseInfo pui, 207 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) { 208 for (String dex : secondaries) { 209 DexUseInfo dui = pui.getDexUseInfoMap().get(dex); 210 assertNotNull(dui); 211 assertEquals(isUsedByOtherApps, dui.isUsedByOtherApps()); 212 assertEquals(ownerUserId, dui.getOwnerUserId()); 213 assertEquals(1, dui.getLoaderIsas().size()); 214 assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa)); 215 } 216 } 217 218 private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) { 219 mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, dexPaths, 220 testData.mLoaderIsa, loaderUserId); 221 } 222 223 private PackageUseInfo getPackageUseInfo(TestData testData) { 224 return mDexManager.getPackageUseInfo(testData.mPackageInfo.packageName); 225 } 226 227 private static PackageInfo getMockPackageInfo(String packageName, int userId) { 228 PackageInfo pi = new PackageInfo(); 229 pi.packageName = packageName; 230 pi.applicationInfo = getMockApplicationInfo(packageName, userId); 231 return pi; 232 } 233 234 private static ApplicationInfo getMockApplicationInfo(String packageName, int userId) { 235 ApplicationInfo ai = new ApplicationInfo(); 236 String codeDir = "/data/app/" + packageName; 237 ai.setBaseCodePath(codeDir + "/base.dex"); 238 ai.setSplitCodePaths(new String[] {codeDir + "/split-1.dex", codeDir + "/split-2.dex"}); 239 ai.dataDir = "/data/user/" + userId + "/" + packageName; 240 ai.packageName = packageName; 241 return ai; 242 } 243 244 private static class TestData { 245 private final PackageInfo mPackageInfo; 246 private final String mLoaderIsa; 247 248 private TestData(String packageName, String loaderIsa, int userId) { 249 mPackageInfo = getMockPackageInfo(packageName, userId); 250 mLoaderIsa = loaderIsa; 251 } 252 253 private String getPackageName() { 254 return mPackageInfo.packageName; 255 } 256 257 List<String> getSecondaryDexPaths() { 258 List<String> paths = new ArrayList<>(); 259 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary1.dex"); 260 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary2.dex"); 261 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary3.dex"); 262 return paths; 263 } 264 265 List<String> getSecondaryDexPathsForOwnUse() { 266 List<String> paths = new ArrayList<>(); 267 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary4.dex"); 268 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary5.dex"); 269 return paths; 270 } 271 272 List<String> getBaseAndSplitDexPaths() { 273 List<String> paths = new ArrayList<>(); 274 paths.add(mPackageInfo.applicationInfo.sourceDir); 275 for (String split : mPackageInfo.applicationInfo.splitSourceDirs) { 276 paths.add(split); 277 } 278 return paths; 279 } 280 } 281} 282