• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.server.pm.dex;
18 
19 import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
20 import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
21 import static com.android.server.pm.dex.PackageDynamicCodeLoading.DynamicCodeFile;
22 import static com.android.server.pm.dex.PackageDynamicCodeLoading.PackageDynamicCode;
23 
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNotEquals;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assert.assertNull;
29 import static org.junit.Assert.assertTrue;
30 
31 import android.content.Context;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.IPackageManager;
34 import android.content.pm.PackageInfo;
35 import android.content.pm.PackageManager;
36 import android.content.res.Resources;
37 import android.os.BatteryManager;
38 import android.os.Build;
39 import android.os.PowerManager;
40 import android.os.UserHandle;
41 
42 import androidx.test.filters.SmallTest;
43 import androidx.test.runner.AndroidJUnit4;
44 
45 import com.android.dx.mockito.inline.extended.ExtendedMockito;
46 import com.android.dx.mockito.inline.extended.StaticMockitoSession;
47 import com.android.server.pm.Installer;
48 import com.android.server.pm.PackageManagerService;
49 
50 import dalvik.system.DelegateLastClassLoader;
51 import dalvik.system.PathClassLoader;
52 import dalvik.system.VMRuntime;
53 
54 import org.junit.After;
55 import org.junit.Before;
56 import org.junit.Test;
57 import org.junit.runner.RunWith;
58 import org.mockito.Mock;
59 import org.mockito.quality.Strictness;
60 
61 import java.io.File;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Collection;
65 import java.util.Collections;
66 import java.util.HashMap;
67 import java.util.List;
68 import java.util.Map;
69 
70 @RunWith(AndroidJUnit4.class)
71 @SmallTest
72 public class DexManagerTests {
73     private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName();
74     private static final String DELEGATE_LAST_CLASS_LOADER_NAME =
75             DelegateLastClassLoader.class.getName();
76     private static final String UNSUPPORTED_CLASS_LOADER_NAME = "unsupported.class_loader";
77 
78     private static final int TEST_BATTERY_LEVEL_CRITICAL = 10;
79     private static final int TEST_BATTERY_LEVEL_DEFAULT = 80;
80 
81     public StaticMockitoSession mMockitoSession;
82     @Mock Installer mInstaller;
83     @Mock IPackageManager mPM;
84     @Mock BatteryManager mMockBatteryManager;
85     @Mock PowerManager mMockPowerManager;
86 
87     private final Object mInstallLock = new Object();
88 
89     private DexManager mDexManager;
90 
91     private TestData mFooUser0;
92     private TestData mBarUser0;
93     private TestData mBarUser1;
94     private TestData mInvalidIsa;
95     private TestData mDoesNotExist;
96 
97     private TestData mBarUser0UnsupportedClassLoader;
98     private TestData mBarUser0DelegateLastClassLoader;
99 
100     private TestData mSystemServerJar;
101     private TestData mSystemServerJarUpdatedContext;
102     private TestData mSystemServerJarInvalid;
103 
104     private int mUser0;
105     private int mUser1;
106 
107     @Before
setup()108     public void setup() {
109         mUser0 = 0;
110         mUser1 = 1;
111 
112         String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
113         String foo = "foo";
114         String bar = "bar";
115 
116         mFooUser0 = new TestData(foo, isa, mUser0, PATH_CLASS_LOADER_NAME);
117         mBarUser0 = new TestData(bar, isa, mUser0, PATH_CLASS_LOADER_NAME);
118         mBarUser1 = new TestData(bar, isa, mUser1, PATH_CLASS_LOADER_NAME);
119         mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0);
120         mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1);
121 
122         mBarUser0UnsupportedClassLoader = new TestData(bar, isa, mUser0,
123                 UNSUPPORTED_CLASS_LOADER_NAME);
124         mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0,
125                 DELEGATE_LAST_CLASS_LOADER_NAME);
126 
127         mSystemServerJar = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME);
128         mSystemServerJarInvalid = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME);
129         mSystemServerJarUpdatedContext = new TestData("android", isa, mUser0,
130                 DELEGATE_LAST_CLASS_LOADER_NAME);
131 
132         // Initialize Static Mocking
133 
134         mMockitoSession = ExtendedMockito.mockitoSession()
135             .initMocks(this)
136             .strictness(Strictness.LENIENT)
137             .startMocking();
138 
139         // Mock....
140 
141         mMockBatteryManager = ExtendedMockito.mock(BatteryManager.class);
142         mMockPowerManager   = ExtendedMockito.mock(PowerManager.class);
143 
144         setDefaultMockValues();
145 
146         Resources mockResources = ExtendedMockito.mock(Resources.class);
147         ExtendedMockito.when(mockResources
148             .getInteger(com.android.internal.R.integer.config_criticalBatteryWarningLevel))
149                 .thenReturn(15);
150 
151         Context mockContext = ExtendedMockito.mock(Context.class);
152         ExtendedMockito.doReturn(mockResources)
153             .when(mockContext)
154                 .getResources();
155         ExtendedMockito.doReturn(mMockBatteryManager)
156             .when(mockContext)
157                 .getSystemService(BatteryManager.class);
158         ExtendedMockito.doReturn(mMockPowerManager)
159             .when(mockContext)
160                 .getSystemService(PowerManager.class);
161 
162         mDexManager = new DexManager(mockContext, /*PackageDexOptimizer*/ null,
163                 mInstaller, mInstallLock, mPM);
164 
165         // Foo and Bar are available to user0.
166         // Only Bar is available to user1;
167         Map<Integer, List<PackageInfo>> existingPackages = new HashMap<>();
168         existingPackages.put(mUser0, Arrays.asList(mFooUser0.mPackageInfo, mBarUser0.mPackageInfo));
169         existingPackages.put(mUser1, Arrays.asList(mBarUser1.mPackageInfo));
170         mDexManager.load(existingPackages);
171     }
172 
173     @After
teardown()174     public void teardown() throws Exception {
175         mMockitoSession.finishMocking();
176     }
177 
setDefaultMockValues()178     private void setDefaultMockValues() {
179         ExtendedMockito.doReturn(BatteryManager.BATTERY_STATUS_DISCHARGING)
180             .when(mMockBatteryManager)
181                 .getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS);
182 
183         ExtendedMockito.doReturn(TEST_BATTERY_LEVEL_DEFAULT)
184             .when(mMockBatteryManager)
185                 .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
186 
187         ExtendedMockito.doReturn(PowerManager.THERMAL_STATUS_NONE)
188             .when(mMockPowerManager)
189                 .getCurrentThermalStatus();
190     }
191 
192     @Test
testNotifyPrimaryUse()193     public void testNotifyPrimaryUse() {
194         // The main dex file and splits are re-loaded by the app.
195         notifyDexLoad(mFooUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0);
196 
197         // Package is not used by others, so we should get nothing back.
198         assertNoUseInfo(mFooUser0);
199 
200         // A package loading its own code is not stored as DCL.
201         assertNoDclInfo(mFooUser0);
202     }
203 
204     @Test
testNotifyPrimaryForeignUse()205     public void testNotifyPrimaryForeignUse() {
206         // Foo loads Bar main apks.
207         notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0);
208 
209         // Bar is used by others now and should be in our records
210         PackageUseInfo pui = getPackageUseInfo(mBarUser0);
211         assertIsUsedByOtherApps(mBarUser0, pui, true);
212         assertTrue(pui.getDexUseInfoMap().isEmpty());
213 
214         // A package loading another package's APK is not DCL (it's not app data).
215         assertNoDclInfo(mBarUser0);
216     }
217 
218     @Test
testNotifySecondary()219     public void testNotifySecondary() {
220         // Foo loads its own secondary files.
221         List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
222         notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
223 
224         PackageUseInfo pui = getPackageUseInfo(mFooUser0);
225         assertIsUsedByOtherApps(mFooUser0, pui, false);
226         assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
227         assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0);
228 
229         assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries);
230     }
231 
232     @Test
testNotifyPrimaryAndSecondary()233     public void testNotifyPrimaryAndSecondary() {
234         List<String> dexFiles = mFooUser0.getBaseAndSplitDexPaths();
235         List<String> secondaries = mFooUser0.getSecondaryDexPaths();
236         int baseAndSplitCount = dexFiles.size();
237         dexFiles.addAll(secondaries);
238 
239         notifyDexLoad(mFooUser0, dexFiles, mUser0);
240 
241         PackageUseInfo pui = getPackageUseInfo(mFooUser0);
242         assertIsUsedByOtherApps(mFooUser0, pui, false);
243         assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
244 
245         String[] allExpectedContexts = DexoptUtils.processContextForDexLoad(
246                 Arrays.asList(mFooUser0.mClassLoader),
247                 Arrays.asList(String.join(File.pathSeparator, dexFiles)));
248         String[] secondaryExpectedContexts = Arrays.copyOfRange(allExpectedContexts,
249                 baseAndSplitCount, dexFiles.size());
250 
251         assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0,
252                 secondaryExpectedContexts);
253 
254         assertHasDclInfo(mFooUser0, mFooUser0, secondaries);
255     }
256 
257     @Test
testNotifySecondaryForeign()258     public void testNotifySecondaryForeign() {
259         // Foo loads bar secondary files.
260         List<String> barSecondaries = mBarUser0.getSecondaryDexPaths();
261         notifyDexLoad(mFooUser0, barSecondaries, mUser0);
262 
263         PackageUseInfo pui = getPackageUseInfo(mBarUser0);
264         assertIsUsedByOtherApps(mBarUser0, pui, false);
265         assertEquals(barSecondaries.size(), pui.getDexUseInfoMap().size());
266         assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0);
267 
268         assertHasDclInfo(mBarUser0, mFooUser0, barSecondaries);
269     }
270 
271     @Test
testNotifySequence()272     public void testNotifySequence() {
273         // Foo loads its own secondary files.
274         List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
275         notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
276         // Foo loads Bar own secondary files.
277         List<String> barSecondaries = mBarUser0.getSecondaryDexPaths();
278         notifyDexLoad(mFooUser0, barSecondaries, mUser0);
279         // Foo loads Bar primary files.
280         notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0);
281         // Bar loads its own secondary files.
282         notifyDexLoad(mBarUser0, barSecondaries, mUser0);
283         // Bar loads some own secondary files which foo didn't load.
284         List<String> barSecondariesForOwnUse = mBarUser0.getSecondaryDexPathsForOwnUse();
285         notifyDexLoad(mBarUser0, barSecondariesForOwnUse, mUser0);
286 
287         // Check bar usage. Should be used by other app (for primary and barSecondaries).
288         PackageUseInfo pui = getPackageUseInfo(mBarUser0);
289         assertIsUsedByOtherApps(mBarUser0, pui, true);
290         assertEquals(barSecondaries.size() + barSecondariesForOwnUse.size(),
291                 pui.getDexUseInfoMap().size());
292 
293         assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0);
294         assertSecondaryUse(mFooUser0, pui, barSecondariesForOwnUse,
295                 /*isUsedByOtherApps*/false, mUser0);
296 
297         // Check foo usage. Should not be used by other app.
298         pui = getPackageUseInfo(mFooUser0);
299         assertIsUsedByOtherApps(mFooUser0, pui, false);
300         assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
301         assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0);
302     }
303 
304     @Test
testNoNotify()305     public void testNoNotify() {
306         // Assert we don't get back data we did not previously record.
307         assertNoUseInfo(mFooUser0);
308         assertNoDclInfo(mFooUser0);
309     }
310 
311     @Test
testInvalidIsa()312     public void testInvalidIsa() {
313         // Notifying with an invalid ISA should be ignored.
314         notifyDexLoad(mInvalidIsa, mInvalidIsa.getSecondaryDexPaths(), mUser0);
315         assertNoUseInfo(mInvalidIsa);
316         assertNoDclInfo(mInvalidIsa);
317     }
318 
319     @Test
testNotExistingPackage()320     public void testNotExistingPackage() {
321         // Notifying about the load of a package which was previously not
322         // register in DexManager#load should be ignored.
323         notifyDexLoad(mDoesNotExist, mDoesNotExist.getBaseAndSplitDexPaths(), mUser0);
324         assertNoUseInfo(mDoesNotExist);
325         assertNoDclInfo(mDoesNotExist);
326     }
327 
328     @Test
testCrossUserAttempt()329     public void testCrossUserAttempt() {
330         // Bar from User1 tries to load secondary dex files from User0 Bar.
331         // Request should be ignored.
332         notifyDexLoad(mBarUser1, mBarUser0.getSecondaryDexPaths(), mUser1);
333         assertNoUseInfo(mBarUser1);
334 
335         assertNoDclInfo(mBarUser1);
336     }
337 
338     @Test
testPackageNotInstalledForUser()339     public void testPackageNotInstalledForUser() {
340         // User1 tries to load Foo which is installed for User0 but not for User1.
341         // Note that the PackageManagerService already filters this out but we
342         // still check that nothing goes unexpected in DexManager.
343         notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser1);
344         assertNoUseInfo(mBarUser1);
345         assertNoUseInfo(mFooUser0);
346 
347         assertNoDclInfo(mBarUser1);
348         assertNoDclInfo(mFooUser0);
349     }
350 
351     @Test
testNotifyPackageInstallUsedByOther()352     public void testNotifyPackageInstallUsedByOther() {
353         TestData newPackage = new TestData("newPackage",
354                 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0);
355 
356         List<String> newSecondaries = newPackage.getSecondaryDexPaths();
357         // Before we notify about the installation of the newPackage if mFoo
358         // is trying to load something from it we should not find it.
359         notifyDexLoad(mFooUser0, newSecondaries, mUser0);
360         assertNoUseInfo(newPackage);
361         assertNoDclInfo(newPackage);
362 
363         // Notify about newPackage install and let mFoo load its dexes.
364         mDexManager.notifyPackageInstalled(newPackage.mPackageInfo, mUser0);
365         notifyDexLoad(mFooUser0, newSecondaries, mUser0);
366 
367         // We should get back the right info.
368         PackageUseInfo pui = getPackageUseInfo(newPackage);
369         assertIsUsedByOtherApps(newPackage, pui, false);
370         assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size());
371         assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/true, mUser0);
372         assertHasDclInfo(newPackage, mFooUser0, newSecondaries);
373     }
374 
375     @Test
testNotifyPackageInstallSelfUse()376     public void testNotifyPackageInstallSelfUse() {
377         TestData newPackage = new TestData("newPackage",
378                 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0);
379 
380         List<String> newSecondaries = newPackage.getSecondaryDexPaths();
381         // Packages should be able to find their own dex files even if the notification about
382         // their installation is delayed.
383         notifyDexLoad(newPackage, newSecondaries, mUser0);
384 
385         PackageUseInfo pui = getPackageUseInfo(newPackage);
386         assertIsUsedByOtherApps(newPackage, pui, false);
387         assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size());
388         assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/false, mUser0);
389         assertHasDclInfo(newPackage, newPackage, newSecondaries);
390     }
391 
392     @Test
testNotifyPackageUpdated()393     public void testNotifyPackageUpdated() {
394         // Foo loads Bar main apks.
395         notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0);
396 
397         // Bar is used by others now and should be in our records.
398         PackageUseInfo pui = getPackageUseInfo(mBarUser0);
399         assertIsUsedByOtherApps(mBarUser0, pui, true);
400         assertTrue(pui.getDexUseInfoMap().isEmpty());
401 
402         // Notify that bar is updated.
403         mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(),
404                 mBarUser0.mPackageInfo.applicationInfo.sourceDir,
405                 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs);
406 
407         // The usedByOtherApps flag should be clear now.
408         pui = getPackageUseInfo(mBarUser0);
409         assertIsUsedByOtherApps(mBarUser0, pui, false);
410     }
411 
412     @Test
testNotifyUsedByIsolatedProcess()413     public void testNotifyUsedByIsolatedProcess() {
414         // Bar loads its own apk but as isolatedProcess.
415         notifyDexLoad(mBarUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0,
416                 /*isolatedProcess=*/ true);
417 
418         // Bar is used by an isolated process and should be marked as usedByOtherApps
419         PackageUseInfo pui = getPackageUseInfo(mBarUser0);
420         assertIsUsedByOtherApps(mBarUser0, pui, true);
421     }
422 
423     @Test
testNotifyPackageUpdatedCodeLocations()424     public void testNotifyPackageUpdatedCodeLocations() {
425         // Simulate a split update.
426         String newSplit = mBarUser0.replaceLastSplit();
427         List<String> newSplits = new ArrayList<>();
428         newSplits.add(newSplit);
429 
430         // We shouldn't find yet the new split as we didn't notify the package update.
431         notifyDexLoad(mFooUser0, newSplits, mUser0);
432         assertNoUseInfo(mBarUser0);
433         assertNoDclInfo(mBarUser0);
434 
435         // Notify that bar is updated. splitSourceDirs will contain the updated path.
436         mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(),
437                 mBarUser0.mPackageInfo.applicationInfo.sourceDir,
438                 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs);
439 
440         // Now, when the split is loaded we will find it and we should mark Bar as usedByOthers.
441         notifyDexLoad(mFooUser0, newSplits, mUser0);
442         PackageUseInfo pui = getPackageUseInfo(mBarUser0);
443         assertIsUsedByOtherApps(newSplits, pui, true);
444 
445         // Primary and split APKs are not recorded as DCL.
446         assertNoDclInfo(mBarUser0);
447     }
448 
449     @Test
testNotifyPackageDataDestroyForOne()450     public void testNotifyPackageDataDestroyForOne() {
451         // Bar loads its own secondary files.
452         notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0);
453         notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1);
454 
455         mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0);
456 
457         // Data for user 1 should still be present
458         PackageUseInfo pui = getPackageUseInfo(mBarUser1);
459         assertSecondaryUse(mBarUser1, pui, mBarUser1.getSecondaryDexPaths(),
460                 /*isUsedByOtherApps*/false, mUser1);
461         assertHasDclInfo(mBarUser1, mBarUser1, mBarUser1.getSecondaryDexPaths());
462 
463         // But not user 0
464         assertNoUseInfo(mBarUser0, mUser0);
465         assertNoDclInfo(mBarUser0, mUser0);
466     }
467 
468     @Test
testNotifyPackageDataDestroyForeignUse()469     public void testNotifyPackageDataDestroyForeignUse() {
470         // Foo loads its own secondary files.
471         List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
472         notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
473 
474         // Bar loads Foo main apks.
475         notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0);
476 
477         mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
478 
479         // Foo should still be around since it's used by other apps but with no
480         // secondary dex info.
481         PackageUseInfo pui = getPackageUseInfo(mFooUser0);
482         assertIsUsedByOtherApps(mFooUser0, pui, true);
483         assertTrue(pui.getDexUseInfoMap().isEmpty());
484 
485         assertNoDclInfo(mFooUser0);
486     }
487 
488     @Test
testNotifyPackageDataDestroyComplete()489     public void testNotifyPackageDataDestroyComplete() {
490         // Foo loads its own secondary files.
491         List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
492         notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
493 
494         mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
495 
496         // Foo should not be around since all its secondary dex info were deleted
497         // and it is not used by other apps.
498         assertNoUseInfo(mFooUser0);
499         assertNoDclInfo(mFooUser0);
500     }
501 
502     @Test
testNotifyPackageDataDestroyForAll()503     public void testNotifyPackageDataDestroyForAll() {
504         // Foo loads its own secondary files.
505         notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0);
506         notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1);
507 
508         mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), UserHandle.USER_ALL);
509 
510         // Bar should not be around since it was removed for all users.
511         assertNoUseInfo(mBarUser0);
512         assertNoDclInfo(mBarUser0);
513     }
514 
515     @Test
testNotifyFrameworkLoad()516     public void testNotifyFrameworkLoad() {
517         String frameworkDex = "/system/framework/com.android.location.provider.jar";
518         // Load a dex file from framework.
519         notifyDexLoad(mFooUser0, Arrays.asList(frameworkDex), mUser0);
520         // The dex file should not be recognized as owned by the package.
521         assertFalse(mDexManager.hasInfoOnPackage(mFooUser0.getPackageName()));
522 
523         assertNull(getPackageDynamicCodeInfo(mFooUser0));
524     }
525 
526     @Test
testNotifySecondaryFromProtected()527     public void testNotifySecondaryFromProtected() {
528         // Foo loads its own secondary files.
529         List<String> fooSecondaries = mFooUser0.getSecondaryDexPathsFromProtectedDirs();
530         notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
531 
532         PackageUseInfo pui = getPackageUseInfo(mFooUser0);
533         assertIsUsedByOtherApps(mFooUser0, pui, false);
534         assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
535         assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0);
536 
537         assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries);
538     }
539 
540     @Test
testNotifyUnsupportedClassLoader()541     public void testNotifyUnsupportedClassLoader() {
542         List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths();
543         notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0);
544 
545         // We don't record the dex usage
546         assertNoUseInfo(mBarUser0UnsupportedClassLoader);
547 
548         // But we do record this as an intance of dynamic code loading
549         assertHasDclInfo(
550                 mBarUser0UnsupportedClassLoader, mBarUser0UnsupportedClassLoader, secondaries);
551     }
552 
553     @Test
testNotifySupportedAndUnsupportedClassLoader()554     public void testNotifySupportedAndUnsupportedClassLoader() {
555         String classPath = String.join(File.pathSeparator, mBarUser0.getSecondaryDexPaths());
556         List<String> classLoaders =
557                 Arrays.asList(PATH_CLASS_LOADER_NAME, UNSUPPORTED_CLASS_LOADER_NAME);
558         List<String> classPaths = Arrays.asList(classPath, classPath);
559         notifyDexLoad(mBarUser0, classLoaders, classPaths, mUser0, /*isolatedProcess=*/ false);
560 
561         assertNoUseInfo(mBarUser0);
562 
563         assertHasDclInfo(mBarUser0, mBarUser0, mBarUser0.getSecondaryDexPaths());
564     }
565 
566     @Test
testNotifyNullClassPath()567     public void testNotifyNullClassPath() {
568         notifyDexLoad(mBarUser0, null, mUser0);
569 
570         assertNoUseInfo(mBarUser0);
571         assertNoDclInfo(mBarUser0);
572     }
573 
574     @Test
testNotifyVariableClassLoader()575     public void testNotifyVariableClassLoader() {
576         // Record bar secondaries with the default PathClassLoader.
577         List<String> secondaries = mBarUser0.getSecondaryDexPaths();
578 
579         notifyDexLoad(mBarUser0, secondaries, mUser0);
580         PackageUseInfo pui = getPackageUseInfo(mBarUser0);
581         assertIsUsedByOtherApps(mBarUser0, pui, false);
582         assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
583         assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
584 
585         // Record bar secondaries again with a different class loader. This will change the context.
586         notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0);
587 
588         pui = getPackageUseInfo(mBarUser0);
589         assertIsUsedByOtherApps(mBarUser0, pui, false);
590         assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
591         // We expect that all the contexts to be changed to variable now.
592         String[] expectedContexts =
593                 Collections.nCopies(secondaries.size(),
594                         PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT).toArray(new String[0]);
595         assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0,
596                 expectedContexts);
597     }
598 
599     @Test
testSystemServerOverwritesContext()600     public void testSystemServerOverwritesContext() {
601         // Record bar secondaries with the default PathClassLoader.
602         List<String> secondaries = mSystemServerJar.getSecondaryDexPaths();
603 
604         notifyDexLoad(mSystemServerJar, secondaries, mUser0);
605         PackageUseInfo pui = getPackageUseInfo(mSystemServerJar);
606         assertSecondaryUse(mSystemServerJar, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
607 
608         // Record bar secondaries again with a different class loader. This will change the context.
609         notifyDexLoad(mSystemServerJarUpdatedContext, secondaries, mUser0);
610 
611         pui = getPackageUseInfo(mSystemServerJar);
612         // We expect that all the contexts to be updated according to the last notify.
613         assertSecondaryUse(mSystemServerJarUpdatedContext, pui, secondaries,
614                 /*isUsedByOtherApps*/false, mUser0);
615     }
616 
617     @Test
testNotifyUnsupportedClassLoaderDoesNotChangeExisting()618     public void testNotifyUnsupportedClassLoaderDoesNotChangeExisting() {
619         List<String> secondaries = mBarUser0.getSecondaryDexPaths();
620 
621         notifyDexLoad(mBarUser0, secondaries, mUser0);
622         PackageUseInfo pui = getPackageUseInfo(mBarUser0);
623         assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
624         assertHasDclInfo(mBarUser0, mBarUser0, secondaries);
625 
626         // Record bar secondaries again with an unsupported class loader. This should not change the
627         // context.
628         notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0);
629         pui = getPackageUseInfo(mBarUser0);
630         assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
631         assertHasDclInfo(mBarUser0, mBarUser0, secondaries);
632     }
633 
634     @Test
testPrimaryAndSecondaryDexLoad()635     public void testPrimaryAndSecondaryDexLoad() {
636         // Foo loads both primary and secondary dexes
637         List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
638         List<String> fooDexes = new ArrayList<>(mFooUser0.getBaseAndSplitDexPaths());
639         int primaryCount = fooDexes.size();
640         fooDexes.addAll(fooSecondaries);
641 
642         notifyDexLoad(mFooUser0, fooDexes, mUser0);
643 
644         PackageUseInfo pui = getPackageUseInfo(mFooUser0);
645         assertIsUsedByOtherApps(mFooUser0, pui, false);
646         assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
647 
648         // Below we want to verify that the secondary dex files within fooDexes have been correctly
649         // reported and their class loader contexts were correctly recorded.
650         //
651         // In order to achieve this we first use DexoptUtils.processContextForDexLoad to compute the
652         // class loader contexts for all the dex files.
653         String[] allClassLoaderContexts = DexoptUtils.processContextForDexLoad(
654                 Arrays.asList(mFooUser0.mClassLoader),
655                 Arrays.asList(String.join(File.pathSeparator, fooDexes)));
656         // Next we filter out the class loader contexts corresponding to non-secondary dex files.
657         String[] secondaryClassLoaderContexts = Arrays.copyOfRange(allClassLoaderContexts,
658                 primaryCount, allClassLoaderContexts.length);
659         assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0,
660                 secondaryClassLoaderContexts);
661 
662         assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries);
663     }
664 
665     @Test
testNotifySecondary_withSharedLibrary()666     public void testNotifySecondary_withSharedLibrary() {
667         // Foo loads its own secondary files.
668         List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
669 
670         String contextSuffix = "{PCL[/system/framework/org.apache.http.legacy.jar]}";
671         String[] expectedContexts = DexoptUtils.processContextForDexLoad(
672                 Arrays.asList(mFooUser0.mClassLoader),
673                 Arrays.asList(String.join(File.pathSeparator, fooSecondaries)));
674         for (int i = 0; i < expectedContexts.length; i++) {
675             expectedContexts[i] += contextSuffix;
676         }
677 
678         notifyDexLoad(mFooUser0, fooSecondaries, expectedContexts, mUser0,
679                 /*isolatedProcess=*/ false);
680 
681         PackageUseInfo pui = getPackageUseInfo(mFooUser0);
682         assertIsUsedByOtherApps(mFooUser0, pui, false);
683         assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
684         assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0,
685                 expectedContexts);
686 
687         assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries);
688     }
689 
690 
691     @Test
testNotifySystemServerUse()692     public void testNotifySystemServerUse() {
693         List<String> dexFiles = new ArrayList<String>();
694         dexFiles.add("/system/framework/foo");
695         notifyDexLoad(mSystemServerJar, dexFiles, mUser0);
696         PackageUseInfo pui = getPackageUseInfo(mSystemServerJar);
697         assertIsUsedByOtherApps(mSystemServerJar, pui, false);
698     }
699 
700     @Test
testNotifySystemServerInvalidUse()701     public void testNotifySystemServerInvalidUse() {
702         List<String> dexFiles = new ArrayList<String>();
703         dexFiles.add("/data/foo");
704         notifyDexLoad(mSystemServerJarInvalid, dexFiles, mUser0);
705         assertNoUseInfo(mSystemServerJarInvalid);
706         assertNoDclInfo(mSystemServerJarInvalid);
707     }
708 
709     @Test
testInstallScenarioToReasonDefault()710     public void testInstallScenarioToReasonDefault() {
711         assertEquals(
712                 PackageManagerService.REASON_INSTALL,
713                 mDexManager.getCompilationReasonForInstallScenario(
714                         PackageManager.INSTALL_SCENARIO_DEFAULT));
715 
716         assertEquals(
717                 PackageManagerService.REASON_INSTALL_FAST,
718                 mDexManager.getCompilationReasonForInstallScenario(
719                         PackageManager.INSTALL_SCENARIO_FAST));
720 
721         assertEquals(
722                 PackageManagerService.REASON_INSTALL_BULK,
723                 mDexManager.getCompilationReasonForInstallScenario(
724                         PackageManager.INSTALL_SCENARIO_BULK));
725 
726         assertEquals(
727                 PackageManagerService.REASON_INSTALL_BULK_SECONDARY,
728                 mDexManager.getCompilationReasonForInstallScenario(
729                         PackageManager.INSTALL_SCENARIO_BULK_SECONDARY));
730     }
731 
732     @Test
testInstallScenarioToReasonThermal()733     public void testInstallScenarioToReasonThermal() {
734         ExtendedMockito.doReturn(PowerManager.THERMAL_STATUS_SEVERE)
735             .when(mMockPowerManager)
736                 .getCurrentThermalStatus();
737 
738         assertEquals(
739                 PackageManagerService.REASON_INSTALL,
740                 mDexManager.getCompilationReasonForInstallScenario(
741                         PackageManager.INSTALL_SCENARIO_DEFAULT));
742 
743         assertEquals(
744                 PackageManagerService.REASON_INSTALL_FAST,
745                 mDexManager.getCompilationReasonForInstallScenario(
746                         PackageManager.INSTALL_SCENARIO_FAST));
747 
748         assertEquals(
749                 PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED,
750                 mDexManager.getCompilationReasonForInstallScenario(
751                         PackageManager.INSTALL_SCENARIO_BULK));
752 
753         assertEquals(
754                 PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED,
755                 mDexManager.getCompilationReasonForInstallScenario(
756                         PackageManager.INSTALL_SCENARIO_BULK_SECONDARY));
757     }
758 
759     @Test
testInstallScenarioToReasonBatteryDischarging()760     public void testInstallScenarioToReasonBatteryDischarging() {
761         ExtendedMockito.doReturn(TEST_BATTERY_LEVEL_CRITICAL)
762             .when(mMockBatteryManager)
763                 .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
764 
765         assertEquals(
766                 PackageManagerService.REASON_INSTALL,
767                 mDexManager.getCompilationReasonForInstallScenario(
768                         PackageManager.INSTALL_SCENARIO_DEFAULT));
769 
770         assertEquals(
771                 PackageManagerService.REASON_INSTALL_FAST,
772                 mDexManager.getCompilationReasonForInstallScenario(
773                         PackageManager.INSTALL_SCENARIO_FAST));
774 
775         assertEquals(
776                 PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED,
777                 mDexManager.getCompilationReasonForInstallScenario(
778                         PackageManager.INSTALL_SCENARIO_BULK));
779 
780         assertEquals(
781                 PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED,
782                 mDexManager.getCompilationReasonForInstallScenario(
783                         PackageManager.INSTALL_SCENARIO_BULK_SECONDARY));
784     }
785 
786     @Test
testInstallScenarioToReasonBatteryCharging()787     public void testInstallScenarioToReasonBatteryCharging() {
788         ExtendedMockito.doReturn(TEST_BATTERY_LEVEL_CRITICAL)
789             .when(mMockBatteryManager)
790                 .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
791 
792         ExtendedMockito.doReturn(BatteryManager.BATTERY_STATUS_CHARGING)
793             .when(mMockBatteryManager)
794                 .getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS);
795 
796         assertEquals(
797                 PackageManagerService.REASON_INSTALL,
798                 mDexManager.getCompilationReasonForInstallScenario(
799                         PackageManager.INSTALL_SCENARIO_DEFAULT));
800 
801         assertEquals(
802                 PackageManagerService.REASON_INSTALL_FAST,
803                 mDexManager.getCompilationReasonForInstallScenario(
804                         PackageManager.INSTALL_SCENARIO_FAST));
805 
806         assertEquals(
807                 PackageManagerService.REASON_INSTALL_BULK,
808                 mDexManager.getCompilationReasonForInstallScenario(
809                         PackageManager.INSTALL_SCENARIO_BULK));
810 
811         assertEquals(
812                 PackageManagerService.REASON_INSTALL_BULK_SECONDARY,
813                 mDexManager.getCompilationReasonForInstallScenario(
814                         PackageManager.INSTALL_SCENARIO_BULK_SECONDARY));
815     }
816 
assertSecondaryUse(TestData testData, PackageUseInfo pui, List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId, String[] expectedContexts)817     private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
818             List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId,
819             String[] expectedContexts) {
820         assertNotNull(expectedContexts);
821         assertEquals(expectedContexts.length, secondaries.size());
822         int index = 0;
823         for (String dex : secondaries) {
824             DexUseInfo dui = pui.getDexUseInfoMap().get(dex);
825             assertNotNull(dui);
826             assertEquals(isUsedByOtherApps, dui.isUsedByOtherApps());
827             assertEquals(ownerUserId, dui.getOwnerUserId());
828             assertEquals(1, dui.getLoaderIsas().size());
829             assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa));
830             assertEquals(expectedContexts[index++], dui.getClassLoaderContext());
831         }
832     }
assertSecondaryUse(TestData testData, PackageUseInfo pui, List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId)833     private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
834             List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) {
835         String[] expectedContexts = DexoptUtils.processContextForDexLoad(
836                 Arrays.asList(testData.mClassLoader),
837                 Arrays.asList(String.join(File.pathSeparator, secondaries)));
838         assertSecondaryUse(testData, pui, secondaries, isUsedByOtherApps, ownerUserId,
839                 expectedContexts);
840     }
841 
assertIsUsedByOtherApps(TestData testData, PackageUseInfo pui, boolean isUsedByOtherApps)842     private void assertIsUsedByOtherApps(TestData testData, PackageUseInfo pui,
843             boolean isUsedByOtherApps) {
844         assertIsUsedByOtherApps(testData.getBaseAndSplitDexPaths(), pui, isUsedByOtherApps);
845     }
846 
assertIsUsedByOtherApps(List<String> codePaths, PackageUseInfo pui, boolean isUsedByOtherApps)847     private void assertIsUsedByOtherApps(List<String> codePaths, PackageUseInfo pui,
848             boolean isUsedByOtherApps) {
849         for (String codePath : codePaths) {
850             assertEquals(codePath, isUsedByOtherApps, pui.isUsedByOtherApps(codePath));
851         }
852     }
853 
notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId)854     private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) {
855         notifyDexLoad(testData, dexPaths, loaderUserId, /*isolatedProcess=*/ false);
856     }
857 
notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId, boolean isolatedProcess)858     private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId,
859             boolean isolatedProcess) {
860         // By default, assume a single class loader in the chain.
861         // This makes writing tests much easier.
862         List<String> classLoaders = Arrays.asList(testData.mClassLoader);
863         List<String> classPaths = dexPaths != null
864                 ? Arrays.<String>asList(String.join(File.pathSeparator, dexPaths)) : null;
865         notifyDexLoad(testData, classLoaders, classPaths, loaderUserId, isolatedProcess);
866     }
867 
notifyDexLoad(TestData testData, List<String> classLoaders, List<String> classPaths, int loaderUserId, boolean isolatedProcess)868     private void notifyDexLoad(TestData testData, List<String> classLoaders,
869             List<String> classPaths, int loaderUserId, boolean isolatedProcess) {
870         String[] classLoaderContexts = computeClassLoaderContexts(classLoaders, classPaths);
871         // We call the internal function so any exceptions thrown cause test failures.
872         List<String> dexPaths = classPaths != null
873                 ? Arrays.asList(classPaths.get(0).split(File.pathSeparator)) : Arrays.asList();
874         notifyDexLoad(testData, dexPaths, classLoaderContexts, loaderUserId, isolatedProcess);
875     }
876 
notifyDexLoad(TestData testData, List<String> dexPaths, String[] classLoaderContexts, int loaderUserId, boolean isolatedProcess)877     private void notifyDexLoad(TestData testData, List<String> dexPaths,
878             String[] classLoaderContexts, int loaderUserId, boolean isolatedProcess) {
879         assertTrue(dexPaths.size() == classLoaderContexts.length);
880         HashMap<String, String> dexPathMapping = new HashMap<>(dexPaths.size());
881         for (int i = 0; i < dexPaths.size(); i++) {
882             dexPathMapping.put(dexPaths.get(i), classLoaderContexts != null
883                     ? classLoaderContexts[i] : PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
884         }
885         mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, dexPathMapping,
886                 testData.mLoaderIsa, loaderUserId, isolatedProcess);
887     }
888 
computeClassLoaderContexts(List<String> classLoaders, List<String> classPaths)889     private String[] computeClassLoaderContexts(List<String> classLoaders,
890             List<String> classPaths) {
891         if (classPaths == null) {
892             return new String[0];
893         }
894         String[] results = DexoptUtils.processContextForDexLoad(classLoaders, classPaths);
895         if (results == null) {
896             results = new String[classPaths.get(0).split(File.pathSeparator).length];
897             Arrays.fill(results, PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
898         }
899         return results;
900     }
901 
getPackageUseInfo(TestData testData)902     private PackageUseInfo getPackageUseInfo(TestData testData) {
903         assertTrue(mDexManager.hasInfoOnPackage(testData.getPackageName()));
904         PackageUseInfo pui = mDexManager.getPackageUseInfoOrDefault(testData.getPackageName());
905         assertNotNull(pui);
906         return pui;
907     }
908 
getPackageDynamicCodeInfo(TestData testData)909     private PackageDynamicCode getPackageDynamicCodeInfo(TestData testData) {
910         return mDexManager.getDynamicCodeLogger()
911                 .getPackageDynamicCodeInfo(testData.getPackageName());
912     }
913 
assertNoUseInfo(TestData testData)914     private void assertNoUseInfo(TestData testData) {
915         assertFalse(mDexManager.hasInfoOnPackage(testData.getPackageName()));
916     }
917 
assertNoUseInfo(TestData testData, int userId)918     private void assertNoUseInfo(TestData testData, int userId) {
919         if (!mDexManager.hasInfoOnPackage(testData.getPackageName())) {
920             return;
921         }
922         PackageUseInfo pui = getPackageUseInfo(testData);
923         for (DexUseInfo dexUseInfo : pui.getDexUseInfoMap().values()) {
924             assertNotEquals(userId, dexUseInfo.getOwnerUserId());
925         }
926     }
927 
assertNoDclInfo(TestData testData)928     private void assertNoDclInfo(TestData testData) {
929         assertNull(getPackageDynamicCodeInfo(testData));
930     }
931 
assertNoDclInfo(TestData testData, int userId)932     private void assertNoDclInfo(TestData testData, int userId) {
933         PackageDynamicCode info = getPackageDynamicCodeInfo(testData);
934         if (info == null) {
935             return;
936         }
937 
938         for (DynamicCodeFile fileInfo : info.mFileUsageMap.values()) {
939             assertNotEquals(userId, fileInfo.mUserId);
940         }
941     }
942 
assertHasDclInfo(TestData owner, TestData loader, List<String> paths)943     private void assertHasDclInfo(TestData owner, TestData loader, List<String> paths) {
944         PackageDynamicCode info = getPackageDynamicCodeInfo(owner);
945         assertNotNull("No DCL data for owner " + owner.getPackageName(), info);
946         for (String path : paths) {
947             DynamicCodeFile fileInfo = info.mFileUsageMap.get(path);
948             assertNotNull("No DCL data for path " + path, fileInfo);
949             assertEquals(PackageDynamicCodeLoading.FILE_TYPE_DEX, fileInfo.mFileType);
950             assertEquals(owner.mUserId, fileInfo.mUserId);
951             assertTrue("No DCL data for loader " + loader.getPackageName(),
952                     fileInfo.mLoadingPackages.contains(loader.getPackageName()));
953         }
954     }
955 
getMockPackageInfo(String packageName, int userId)956     private static PackageInfo getMockPackageInfo(String packageName, int userId) {
957         PackageInfo pi = new PackageInfo();
958         pi.packageName = packageName;
959         pi.applicationInfo = getMockApplicationInfo(packageName, userId);
960         return pi;
961     }
962 
getMockApplicationInfo(String packageName, int userId)963     private static ApplicationInfo getMockApplicationInfo(String packageName, int userId) {
964         ApplicationInfo ai = new ApplicationInfo();
965         String codeDir = "/data/app/" + packageName;
966         ai.setBaseCodePath(codeDir + "/base.dex");
967         ai.setSplitCodePaths(new String[] {codeDir + "/split-1.dex", codeDir + "/split-2.dex"});
968         ai.dataDir = "/data/user/" + userId + "/" + packageName;
969         ai.deviceProtectedDataDir = "/data/user_de/" + userId + "/" + packageName;
970         ai.credentialProtectedDataDir = "/data/user_ce/" + userId + "/" + packageName;
971         ai.packageName = packageName;
972         return ai;
973     }
974 
975     private static class TestData {
976         private final PackageInfo mPackageInfo;
977         private final String mLoaderIsa;
978         private final String mClassLoader;
979         private final int mUserId;
980 
TestData(String packageName, String loaderIsa, int userId, String classLoader)981         private TestData(String packageName, String loaderIsa, int userId, String classLoader) {
982             mPackageInfo = getMockPackageInfo(packageName, userId);
983             mLoaderIsa = loaderIsa;
984             mClassLoader = classLoader;
985             mUserId = userId;
986         }
987 
TestData(String packageName, String loaderIsa, int userId)988         private TestData(String packageName, String loaderIsa, int userId) {
989             this(packageName, loaderIsa, userId, PATH_CLASS_LOADER_NAME);
990         }
991 
getPackageName()992         private String getPackageName() {
993             return mPackageInfo.packageName;
994         }
995 
getSecondaryDexPaths()996         List<String> getSecondaryDexPaths() {
997             List<String> paths = new ArrayList<>();
998             paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary1.dex");
999             paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary2.dex");
1000             paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary3.dex");
1001             return paths;
1002         }
1003 
getSecondaryDexPathsForOwnUse()1004         List<String> getSecondaryDexPathsForOwnUse() {
1005             List<String> paths = new ArrayList<>();
1006             paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary4.dex");
1007             paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary5.dex");
1008             return paths;
1009         }
1010 
getSecondaryDexPathsFromProtectedDirs()1011         List<String> getSecondaryDexPathsFromProtectedDirs() {
1012             List<String> paths = new ArrayList<>();
1013             paths.add(mPackageInfo.applicationInfo.deviceProtectedDataDir + "/secondary6.dex");
1014             paths.add(mPackageInfo.applicationInfo.credentialProtectedDataDir + "/secondary7.dex");
1015             return paths;
1016         }
1017 
getBaseAndSplitDexPaths()1018         List<String> getBaseAndSplitDexPaths() {
1019             List<String> paths = new ArrayList<>();
1020             paths.add(mPackageInfo.applicationInfo.sourceDir);
1021             Collections.addAll(paths, mPackageInfo.applicationInfo.splitSourceDirs);
1022             return paths;
1023         }
1024 
replaceLastSplit()1025         String replaceLastSplit() {
1026             int length = mPackageInfo.applicationInfo.splitSourceDirs.length;
1027             // Add an extra bogus dex extension to simulate a new split name.
1028             mPackageInfo.applicationInfo.splitSourceDirs[length - 1] += ".dex";
1029             return mPackageInfo.applicationInfo.splitSourceDirs[length - 1];
1030         }
1031     }
1032 
shouldPackageRunOob(boolean isDefaultEnabled, String whitelist, Collection<String> packageNamesInSameProcess)1033     private boolean shouldPackageRunOob(boolean isDefaultEnabled, String whitelist,
1034             Collection<String> packageNamesInSameProcess) {
1035         return DexManager.isPackageSelectedToRunOobInternal(
1036                 isDefaultEnabled, whitelist, packageNamesInSameProcess);
1037     }
1038 
1039     @Test
testOobPackageSelectionDefault()1040     public void testOobPackageSelectionDefault() {
1041         // Feature is off by default, not overriden
1042         assertFalse(shouldPackageRunOob(false, "ALL", null));
1043     }
1044 
1045     @Test
testOobPackageSelectionWhitelist()1046     public void testOobPackageSelectionWhitelist() {
1047         // Various allowlist of apps to run in OOB mode.
1048         final String kWhitelistApp0 = "com.priv.app0";
1049         final String kWhitelistApp1 = "com.priv.app1";
1050         final String kWhitelistApp2 = "com.priv.app2";
1051         final String kWhitelistApp1AndApp2 = "com.priv.app1,com.priv.app2";
1052 
1053         // Packages that shares the targeting process.
1054         final Collection<String> runningPackages = Arrays.asList("com.priv.app1", "com.priv.app2");
1055 
1056         // Feature is off, allowlist does not matter
1057         assertFalse(shouldPackageRunOob(false, kWhitelistApp0, runningPackages));
1058         assertFalse(shouldPackageRunOob(false, kWhitelistApp1, runningPackages));
1059         assertFalse(shouldPackageRunOob(false, "", runningPackages));
1060         assertFalse(shouldPackageRunOob(false, "ALL", runningPackages));
1061 
1062         // Feature is on, app not in allowlist
1063         assertFalse(shouldPackageRunOob(true, kWhitelistApp0, runningPackages));
1064         assertFalse(shouldPackageRunOob(true, "", runningPackages));
1065 
1066         // Feature is on, app in allowlist
1067         assertTrue(shouldPackageRunOob(true, kWhitelistApp1, runningPackages));
1068         assertTrue(shouldPackageRunOob(true, kWhitelistApp2, runningPackages));
1069         assertTrue(shouldPackageRunOob(true, kWhitelistApp1AndApp2, runningPackages));
1070         assertTrue(shouldPackageRunOob(true, "ALL", runningPackages));
1071     }
1072 }
1073