DexManagerTests.java revision 2dfc1b3e125860221bc67835c2d5c99198a12f8a
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.content.pm.ApplicationInfo; 20import android.content.pm.PackageInfo; 21import android.os.Build; 22import android.os.UserHandle; 23import android.support.test.filters.SmallTest; 24import android.support.test.runner.AndroidJUnit4; 25 26import dalvik.system.VMRuntime; 27 28import java.util.ArrayList; 29import java.util.Arrays; 30import java.util.HashMap; 31import java.util.List; 32import java.util.Map; 33 34import org.junit.Before; 35import org.junit.Test; 36import org.junit.runner.RunWith; 37 38import static org.junit.Assert.assertEquals; 39import static org.junit.Assert.assertFalse; 40import static org.junit.Assert.assertNotNull; 41import static org.junit.Assert.assertNull; 42import static org.junit.Assert.assertTrue; 43import static org.junit.Assert.fail; 44 45import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo; 46import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; 47 48@RunWith(AndroidJUnit4.class) 49@SmallTest 50public class DexManagerTests { 51 private DexManager mDexManager; 52 53 private TestData mFooUser0; 54 private TestData mBarUser0; 55 private TestData mBarUser1; 56 private TestData mInvalidIsa; 57 private TestData mDoesNotExist; 58 59 private int mUser0; 60 private int mUser1; 61 62 @Before 63 public void setup() { 64 mUser0 = 0; 65 mUser1 = 1; 66 67 String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); 68 String foo = "foo"; 69 String bar = "bar"; 70 71 mFooUser0 = new TestData(foo, isa, mUser0); 72 mBarUser0 = new TestData(bar, isa, mUser0); 73 mBarUser1 = new TestData(bar, isa, mUser1); 74 mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0); 75 mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1); 76 77 mDexManager = new DexManager(null, null, null, null); 78 79 // Foo and Bar are available to user0. 80 // Only Bar is available to user1; 81 Map<Integer, List<PackageInfo>> existingPackages = new HashMap<>(); 82 existingPackages.put(mUser0, Arrays.asList(mFooUser0.mPackageInfo, mBarUser0.mPackageInfo)); 83 existingPackages.put(mUser1, Arrays.asList(mBarUser1.mPackageInfo)); 84 mDexManager.load(existingPackages); 85 } 86 87 @Test 88 public void testNotifyPrimaryUse() { 89 // The main dex file and splits are re-loaded by the app. 90 notifyDexLoad(mFooUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); 91 92 // Package is not used by others, so we should get nothing back. 93 assertNull(getPackageUseInfo(mFooUser0)); 94 } 95 96 @Test 97 public void testNotifyPrimaryForeignUse() { 98 // Foo loads Bar main apks. 99 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 100 101 // Bar is used by others now and should be in our records 102 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 103 assertNotNull(pui); 104 assertTrue(pui.isUsedByOtherApps()); 105 assertTrue(pui.getDexUseInfoMap().isEmpty()); 106 } 107 108 @Test 109 public void testNotifySecondary() { 110 // Foo loads its own secondary files. 111 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 112 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 113 114 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 115 assertNotNull(pui); 116 assertFalse(pui.isUsedByOtherApps()); 117 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 118 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 119 } 120 121 @Test 122 public void testNotifySecondaryForeign() { 123 // Foo loads bar secondary files. 124 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 125 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 126 127 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 128 assertNotNull(pui); 129 assertFalse(pui.isUsedByOtherApps()); 130 assertEquals(barSecondaries.size(), pui.getDexUseInfoMap().size()); 131 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 132 } 133 134 @Test 135 public void testNotifySequence() { 136 // Foo loads its own secondary files. 137 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 138 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 139 // Foo loads Bar own secondary files. 140 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 141 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 142 // Foo loads Bar primary files. 143 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 144 // Bar loads its own secondary files. 145 notifyDexLoad(mBarUser0, barSecondaries, mUser0); 146 // Bar loads some own secondary files which foo didn't load. 147 List<String> barSecondariesForOwnUse = mBarUser0.getSecondaryDexPathsForOwnUse(); 148 notifyDexLoad(mBarUser0, barSecondariesForOwnUse, mUser0); 149 150 // Check bar usage. Should be used by other app (for primary and barSecondaries). 151 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 152 assertNotNull(pui); 153 assertTrue(pui.isUsedByOtherApps()); 154 assertEquals(barSecondaries.size() + barSecondariesForOwnUse.size(), 155 pui.getDexUseInfoMap().size()); 156 157 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 158 assertSecondaryUse(mFooUser0, pui, barSecondariesForOwnUse, 159 /*isUsedByOtherApps*/false, mUser0); 160 161 // Check foo usage. Should not be used by other app. 162 pui = getPackageUseInfo(mFooUser0); 163 assertNotNull(pui); 164 assertFalse(pui.isUsedByOtherApps()); 165 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 166 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 167 } 168 169 @Test 170 public void testPackageUseInfoNotFound() { 171 // Assert we don't get back data we did not previously record. 172 assertNull(getPackageUseInfo(mFooUser0)); 173 } 174 175 @Test 176 public void testInvalidIsa() { 177 // Notifying with an invalid ISA should be ignored. 178 notifyDexLoad(mInvalidIsa, mInvalidIsa.getSecondaryDexPaths(), mUser0); 179 assertNull(getPackageUseInfo(mInvalidIsa)); 180 } 181 182 @Test 183 public void testNotExistingPackate() { 184 // Notifying about the load of a package which was previously not 185 // register in DexManager#load should be ignored. 186 notifyDexLoad(mDoesNotExist, mDoesNotExist.getBaseAndSplitDexPaths(), mUser0); 187 assertNull(getPackageUseInfo(mDoesNotExist)); 188 } 189 190 @Test 191 public void testCrossUserAttempt() { 192 // Bar from User1 tries to load secondary dex files from User0 Bar. 193 // Request should be ignored. 194 notifyDexLoad(mBarUser1, mBarUser0.getSecondaryDexPaths(), mUser1); 195 assertNull(getPackageUseInfo(mBarUser1)); 196 } 197 198 @Test 199 public void testPackageNotInstalledForUser() { 200 // User1 tries to load Foo which is installed for User0 but not for User1. 201 // Note that the PackageManagerService already filters this out but we 202 // still check that nothing goes unexpected in DexManager. 203 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser1); 204 assertNull(getPackageUseInfo(mBarUser1)); 205 } 206 207 @Test 208 public void testNotifyPackageInstallUsedByOther() { 209 TestData newPackage = new TestData("newPackage", 210 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0); 211 212 List<String> newSecondaries = newPackage.getSecondaryDexPaths(); 213 // Before we notify about the installation of the newPackage if mFoo 214 // is trying to load something from it we should not find it. 215 notifyDexLoad(mFooUser0, newSecondaries, mUser0); 216 assertNull(getPackageUseInfo(newPackage)); 217 218 // Notify about newPackage install and let mFoo load its dexes. 219 mDexManager.notifyPackageInstalled(newPackage.mPackageInfo, mUser0); 220 notifyDexLoad(mFooUser0, newSecondaries, mUser0); 221 222 // We should get back the right info. 223 PackageUseInfo pui = getPackageUseInfo(newPackage); 224 assertNotNull(pui); 225 assertFalse(pui.isUsedByOtherApps()); 226 assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size()); 227 assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/true, mUser0); 228 } 229 230 @Test 231 public void testNotifyPackageInstallSelfUse() { 232 TestData newPackage = new TestData("newPackage", 233 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0); 234 235 List<String> newSecondaries = newPackage.getSecondaryDexPaths(); 236 // Packages should be able to find their own dex files even if the notification about 237 // their installation is delayed. 238 notifyDexLoad(newPackage, newSecondaries, mUser0); 239 240 PackageUseInfo pui = getPackageUseInfo(newPackage); 241 assertNotNull(pui); 242 assertFalse(pui.isUsedByOtherApps()); 243 assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size()); 244 assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/false, mUser0); 245 } 246 247 @Test 248 public void testNotifyPackageUpdated() { 249 // Foo loads Bar main apks. 250 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 251 252 // Bar is used by others now and should be in our records. 253 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 254 assertNotNull(pui); 255 assertTrue(pui.isUsedByOtherApps()); 256 assertTrue(pui.getDexUseInfoMap().isEmpty()); 257 258 // Notify that bar is updated. 259 mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(), 260 mBarUser0.mPackageInfo.applicationInfo.sourceDir, 261 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs); 262 263 // The usedByOtherApps flag should be clear now. 264 pui = getPackageUseInfo(mBarUser0); 265 assertNotNull(pui); 266 assertFalse(pui.isUsedByOtherApps()); 267 } 268 269 @Test 270 public void testNotifyPackageUpdatedCodeLocations() { 271 // Simulate a split update. 272 String newSplit = mBarUser0.replaceLastSplit(); 273 List<String> newSplits = new ArrayList<>(); 274 newSplits.add(newSplit); 275 276 // We shouldn't find yet the new split as we didn't notify the package update. 277 notifyDexLoad(mFooUser0, newSplits, mUser0); 278 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 279 assertNull(pui); 280 281 // Notify that bar is updated. splitSourceDirs will contain the updated path. 282 mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(), 283 mBarUser0.mPackageInfo.applicationInfo.sourceDir, 284 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs); 285 286 // Now, when the split is loaded we will find it and we should mark Bar as usedByOthers. 287 notifyDexLoad(mFooUser0, newSplits, mUser0); 288 pui = getPackageUseInfo(mBarUser0); 289 assertNotNull(pui); 290 assertTrue(pui.isUsedByOtherApps()); 291 } 292 293 @Test 294 public void testNotifyPackageDataDestroyForOne() { 295 // Bar loads its own secondary files. 296 notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0); 297 notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1); 298 299 mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0); 300 301 // Bar should not be around since it was removed for all users. 302 PackageUseInfo pui = getPackageUseInfo(mBarUser1); 303 assertNotNull(pui); 304 assertSecondaryUse(mBarUser1, pui, mBarUser1.getSecondaryDexPaths(), 305 /*isUsedByOtherApps*/false, mUser1); 306 } 307 308 @Test 309 public void testNotifyPackageDataDestroyForeignUse() { 310 // Foo loads its own secondary files. 311 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 312 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 313 314 // Bar loads Foo main apks. 315 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); 316 317 mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); 318 319 // Foo should still be around since it's used by other apps but with no 320 // secondary dex info. 321 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 322 assertNotNull(pui); 323 assertTrue(pui.isUsedByOtherApps()); 324 assertTrue(pui.getDexUseInfoMap().isEmpty()); 325 } 326 327 @Test 328 public void testNotifyPackageDataDestroyComplete() { 329 // Foo loads its own secondary files. 330 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 331 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 332 333 mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); 334 335 // Foo should not be around since all its secondary dex info were deleted 336 // and it is not used by other apps. 337 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 338 assertNull(pui); 339 } 340 341 @Test 342 public void testNotifyPackageDataDestroyForAll() { 343 // Foo loads its own secondary files. 344 notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0); 345 notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1); 346 347 mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), UserHandle.USER_ALL); 348 349 // Bar should not be around since it was removed for all users. 350 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 351 assertNull(pui); 352 } 353 354 @Test 355 public void testNotifyFrameworkLoad() { 356 String frameworkDex = "/system/framework/com.android.location.provider.jar"; 357 // Load a dex file from framework. 358 notifyDexLoad(mFooUser0, Arrays.asList(frameworkDex), mUser0); 359 // The dex file should not be recognized as a package. 360 assertNull(mDexManager.getPackageUseInfo(frameworkDex)); 361 } 362 363 private void assertSecondaryUse(TestData testData, PackageUseInfo pui, 364 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) { 365 for (String dex : secondaries) { 366 DexUseInfo dui = pui.getDexUseInfoMap().get(dex); 367 assertNotNull(dui); 368 assertEquals(isUsedByOtherApps, dui.isUsedByOtherApps()); 369 assertEquals(ownerUserId, dui.getOwnerUserId()); 370 assertEquals(1, dui.getLoaderIsas().size()); 371 assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa)); 372 } 373 } 374 375 private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) { 376 mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, dexPaths, 377 testData.mLoaderIsa, loaderUserId); 378 } 379 380 private PackageUseInfo getPackageUseInfo(TestData testData) { 381 return mDexManager.getPackageUseInfo(testData.mPackageInfo.packageName); 382 } 383 384 private static PackageInfo getMockPackageInfo(String packageName, int userId) { 385 PackageInfo pi = new PackageInfo(); 386 pi.packageName = packageName; 387 pi.applicationInfo = getMockApplicationInfo(packageName, userId); 388 return pi; 389 } 390 391 private static ApplicationInfo getMockApplicationInfo(String packageName, int userId) { 392 ApplicationInfo ai = new ApplicationInfo(); 393 String codeDir = "/data/app/" + packageName; 394 ai.setBaseCodePath(codeDir + "/base.dex"); 395 ai.setSplitCodePaths(new String[] {codeDir + "/split-1.dex", codeDir + "/split-2.dex"}); 396 ai.dataDir = "/data/user/" + userId + "/" + packageName; 397 ai.packageName = packageName; 398 return ai; 399 } 400 401 private static class TestData { 402 private final PackageInfo mPackageInfo; 403 private final String mLoaderIsa; 404 405 private TestData(String packageName, String loaderIsa, int userId) { 406 mPackageInfo = getMockPackageInfo(packageName, userId); 407 mLoaderIsa = loaderIsa; 408 } 409 410 private String getPackageName() { 411 return mPackageInfo.packageName; 412 } 413 414 List<String> getSecondaryDexPaths() { 415 List<String> paths = new ArrayList<>(); 416 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary1.dex"); 417 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary2.dex"); 418 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary3.dex"); 419 return paths; 420 } 421 422 List<String> getSecondaryDexPathsForOwnUse() { 423 List<String> paths = new ArrayList<>(); 424 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary4.dex"); 425 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary5.dex"); 426 return paths; 427 } 428 429 List<String> getBaseAndSplitDexPaths() { 430 List<String> paths = new ArrayList<>(); 431 paths.add(mPackageInfo.applicationInfo.sourceDir); 432 for (String split : mPackageInfo.applicationInfo.splitSourceDirs) { 433 paths.add(split); 434 } 435 return paths; 436 } 437 438 String replaceLastSplit() { 439 int length = mPackageInfo.applicationInfo.splitSourceDirs.length; 440 // Add an extra bogus dex extension to simulate a new split name. 441 mPackageInfo.applicationInfo.splitSourceDirs[length - 1] += ".dex"; 442 return mPackageInfo.applicationInfo.splitSourceDirs[length - 1]; 443 } 444 } 445} 446