blob: 2a3ccbd965bc18336453d4c0dbfbd8e8ad04e336 [file] [log] [blame]
Calin Juravleb8976d82016-12-16 16:22:00 +00001/*
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
Brett Chabot8091d9e2019-02-26 14:52:33 -080019import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
20import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
21
22import static org.junit.Assert.assertEquals;
23import static org.junit.Assert.assertFalse;
24import static org.junit.Assert.assertNotNull;
25import static org.junit.Assert.assertTrue;
26import static org.mockito.ArgumentMatchers.any;
27import static org.mockito.ArgumentMatchers.anyInt;
28import static org.mockito.ArgumentMatchers.anyString;
29import static org.mockito.Mockito.times;
30import static org.mockito.Mockito.verify;
31import static org.mockito.Mockito.when;
32
Calin Juravleb8976d82016-12-16 16:22:00 +000033import android.content.pm.ApplicationInfo;
Alan Stokesa0023602017-10-16 12:31:44 +010034import android.content.pm.IPackageManager;
Calin Juravleb8976d82016-12-16 16:22:00 +000035import android.content.pm.PackageInfo;
Calin Juravle99dd37b2017-02-22 19:05:06 -080036import android.os.Build;
37import android.os.UserHandle;
Brett Chabot8091d9e2019-02-26 14:52:33 -080038
39import androidx.test.filters.SmallTest;
40import androidx.test.runner.AndroidJUnit4;
Calin Juravleb8976d82016-12-16 16:22:00 +000041
Alan Stokesa0023602017-10-16 12:31:44 +010042import com.android.server.pm.Installer;
43
Calin Juravlef1ff36f2017-07-22 12:33:41 -070044import dalvik.system.DelegateLastClassLoader;
45import dalvik.system.PathClassLoader;
Calin Juravleb8976d82016-12-16 16:22:00 +000046import dalvik.system.VMRuntime;
47
Calin Juravleb8976d82016-12-16 16:22:00 +000048import org.junit.Before;
Alan Stokesa0023602017-10-16 12:31:44 +010049import org.junit.Rule;
Calin Juravleb8976d82016-12-16 16:22:00 +000050import org.junit.Test;
51import org.junit.runner.RunWith;
Alan Stokesa0023602017-10-16 12:31:44 +010052import org.mockito.Mock;
53import org.mockito.junit.MockitoJUnit;
54import org.mockito.junit.MockitoRule;
55import org.mockito.quality.Strictness;
Calin Juravleb8976d82016-12-16 16:22:00 +000056
Brett Chabot8091d9e2019-02-26 14:52:33 -080057import java.io.File;
58import java.util.ArrayList;
59import java.util.Arrays;
60import java.util.Collections;
61import java.util.HashMap;
62import java.util.List;
63import java.util.Map;
Calin Juravleb8976d82016-12-16 16:22:00 +000064
65@RunWith(AndroidJUnit4.class)
66@SmallTest
67public class DexManagerTests {
Calin Juravlef1ff36f2017-07-22 12:33:41 -070068 private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName();
69 private static final String DELEGATE_LAST_CLASS_LOADER_NAME =
70 DelegateLastClassLoader.class.getName();
Alan Stokesb6c3a602018-11-02 12:10:42 +000071 private static final String UNSUPPORTED_CLASS_LOADER_NAME = "unsupported.class_loader";
Calin Juravlef1ff36f2017-07-22 12:33:41 -070072
Alan Stokesa0023602017-10-16 12:31:44 +010073 @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
74 @Mock Installer mInstaller;
75 @Mock IPackageManager mPM;
76 private final Object mInstallLock = new Object();
77 @Mock DexManager.Listener mListener;
78
Calin Juravleb8976d82016-12-16 16:22:00 +000079 private DexManager mDexManager;
80
81 private TestData mFooUser0;
82 private TestData mBarUser0;
83 private TestData mBarUser1;
84 private TestData mInvalidIsa;
85 private TestData mDoesNotExist;
86
Calin Juravlef1ff36f2017-07-22 12:33:41 -070087 private TestData mBarUser0UnsupportedClassLoader;
88 private TestData mBarUser0DelegateLastClassLoader;
89
Calin Juravleb8976d82016-12-16 16:22:00 +000090 private int mUser0;
91 private int mUser1;
Calin Juravle99dd37b2017-02-22 19:05:06 -080092
Calin Juravleb8976d82016-12-16 16:22:00 +000093 @Before
94 public void setup() {
Calin Juravleb8976d82016-12-16 16:22:00 +000095 mUser0 = 0;
96 mUser1 = 1;
97
98 String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
99 String foo = "foo";
100 String bar = "bar";
101
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700102 mFooUser0 = new TestData(foo, isa, mUser0, PATH_CLASS_LOADER_NAME);
103 mBarUser0 = new TestData(bar, isa, mUser0, PATH_CLASS_LOADER_NAME);
104 mBarUser1 = new TestData(bar, isa, mUser1, PATH_CLASS_LOADER_NAME);
Calin Juravleb8976d82016-12-16 16:22:00 +0000105 mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0);
106 mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1);
107
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700108 mBarUser0UnsupportedClassLoader = new TestData(bar, isa, mUser0,
Alan Stokesb6c3a602018-11-02 12:10:42 +0000109 UNSUPPORTED_CLASS_LOADER_NAME);
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700110 mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0,
111 DELEGATE_LAST_CLASS_LOADER_NAME);
112
Alan Stokesa0023602017-10-16 12:31:44 +0100113 mDexManager = new DexManager(
Victor Hsieh785d6182018-04-19 14:26:28 -0700114 /*Context*/ null, mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock,
115 mListener);
Calin Juravleb8976d82016-12-16 16:22:00 +0000116
117 // Foo and Bar are available to user0.
118 // Only Bar is available to user1;
119 Map<Integer, List<PackageInfo>> existingPackages = new HashMap<>();
120 existingPackages.put(mUser0, Arrays.asList(mFooUser0.mPackageInfo, mBarUser0.mPackageInfo));
121 existingPackages.put(mUser1, Arrays.asList(mBarUser1.mPackageInfo));
122 mDexManager.load(existingPackages);
123 }
124
125 @Test
126 public void testNotifyPrimaryUse() {
127 // The main dex file and splits are re-loaded by the app.
128 notifyDexLoad(mFooUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0);
129
130 // Package is not used by others, so we should get nothing back.
Calin Juravle3b74c412017-08-03 19:48:37 -0700131 assertNoUseInfo(mFooUser0);
Calin Juravleb8976d82016-12-16 16:22:00 +0000132 }
133
134 @Test
135 public void testNotifyPrimaryForeignUse() {
136 // Foo loads Bar main apks.
137 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0);
138
139 // Bar is used by others now and should be in our records
140 PackageUseInfo pui = getPackageUseInfo(mBarUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700141 assertIsUsedByOtherApps(mBarUser0, pui, true);
Calin Juravleb8976d82016-12-16 16:22:00 +0000142 assertTrue(pui.getDexUseInfoMap().isEmpty());
143 }
144
145 @Test
146 public void testNotifySecondary() {
147 // Foo loads its own secondary files.
148 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
149 notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
150
151 PackageUseInfo pui = getPackageUseInfo(mFooUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700152 assertIsUsedByOtherApps(mFooUser0, pui, false);
Calin Juravleb8976d82016-12-16 16:22:00 +0000153 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
154 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0);
155 }
156
157 @Test
158 public void testNotifySecondaryForeign() {
159 // Foo loads bar secondary files.
160 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths();
161 notifyDexLoad(mFooUser0, barSecondaries, mUser0);
162
163 PackageUseInfo pui = getPackageUseInfo(mBarUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700164 assertIsUsedByOtherApps(mBarUser0, pui, false);
Calin Juravleb8976d82016-12-16 16:22:00 +0000165 assertEquals(barSecondaries.size(), pui.getDexUseInfoMap().size());
166 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0);
167 }
168
169 @Test
170 public void testNotifySequence() {
171 // Foo loads its own secondary files.
172 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
173 notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
174 // Foo loads Bar own secondary files.
175 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths();
176 notifyDexLoad(mFooUser0, barSecondaries, mUser0);
177 // Foo loads Bar primary files.
178 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0);
179 // Bar loads its own secondary files.
180 notifyDexLoad(mBarUser0, barSecondaries, mUser0);
181 // Bar loads some own secondary files which foo didn't load.
182 List<String> barSecondariesForOwnUse = mBarUser0.getSecondaryDexPathsForOwnUse();
183 notifyDexLoad(mBarUser0, barSecondariesForOwnUse, mUser0);
184
185 // Check bar usage. Should be used by other app (for primary and barSecondaries).
186 PackageUseInfo pui = getPackageUseInfo(mBarUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700187 assertIsUsedByOtherApps(mBarUser0, pui, true);
Calin Juravleb8976d82016-12-16 16:22:00 +0000188 assertEquals(barSecondaries.size() + barSecondariesForOwnUse.size(),
189 pui.getDexUseInfoMap().size());
190
191 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0);
192 assertSecondaryUse(mFooUser0, pui, barSecondariesForOwnUse,
193 /*isUsedByOtherApps*/false, mUser0);
194
195 // Check foo usage. Should not be used by other app.
196 pui = getPackageUseInfo(mFooUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700197 assertIsUsedByOtherApps(mFooUser0, pui, false);
Calin Juravleb8976d82016-12-16 16:22:00 +0000198 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
199 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0);
200 }
201
202 @Test
203 public void testPackageUseInfoNotFound() {
204 // Assert we don't get back data we did not previously record.
Calin Juravle3b74c412017-08-03 19:48:37 -0700205 assertNoUseInfo(mFooUser0);
Calin Juravleb8976d82016-12-16 16:22:00 +0000206 }
207
208 @Test
209 public void testInvalidIsa() {
210 // Notifying with an invalid ISA should be ignored.
211 notifyDexLoad(mInvalidIsa, mInvalidIsa.getSecondaryDexPaths(), mUser0);
Calin Juravle3b74c412017-08-03 19:48:37 -0700212 assertNoUseInfo(mInvalidIsa);
Calin Juravleb8976d82016-12-16 16:22:00 +0000213 }
214
215 @Test
Calin Juravle52a452c2017-08-04 01:42:17 -0700216 public void testNotExistingPackage() {
Calin Juravleb8976d82016-12-16 16:22:00 +0000217 // Notifying about the load of a package which was previously not
218 // register in DexManager#load should be ignored.
219 notifyDexLoad(mDoesNotExist, mDoesNotExist.getBaseAndSplitDexPaths(), mUser0);
Calin Juravle3b74c412017-08-03 19:48:37 -0700220 assertNoUseInfo(mDoesNotExist);
Calin Juravleb8976d82016-12-16 16:22:00 +0000221 }
222
223 @Test
224 public void testCrossUserAttempt() {
225 // Bar from User1 tries to load secondary dex files from User0 Bar.
226 // Request should be ignored.
227 notifyDexLoad(mBarUser1, mBarUser0.getSecondaryDexPaths(), mUser1);
Calin Juravle3b74c412017-08-03 19:48:37 -0700228 assertNoUseInfo(mBarUser1);
Calin Juravleb8976d82016-12-16 16:22:00 +0000229 }
230
231 @Test
232 public void testPackageNotInstalledForUser() {
233 // User1 tries to load Foo which is installed for User0 but not for User1.
234 // Note that the PackageManagerService already filters this out but we
235 // still check that nothing goes unexpected in DexManager.
236 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser1);
Calin Juravle3b74c412017-08-03 19:48:37 -0700237 assertNoUseInfo(mBarUser1);
Calin Juravleb8976d82016-12-16 16:22:00 +0000238 }
239
Calin Juravle0d4b8f82017-01-23 23:34:25 -0800240 @Test
241 public void testNotifyPackageInstallUsedByOther() {
242 TestData newPackage = new TestData("newPackage",
243 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0);
244
245 List<String> newSecondaries = newPackage.getSecondaryDexPaths();
246 // Before we notify about the installation of the newPackage if mFoo
247 // is trying to load something from it we should not find it.
248 notifyDexLoad(mFooUser0, newSecondaries, mUser0);
Calin Juravle3b74c412017-08-03 19:48:37 -0700249 assertNoUseInfo(newPackage);
Calin Juravle0d4b8f82017-01-23 23:34:25 -0800250
251 // Notify about newPackage install and let mFoo load its dexes.
252 mDexManager.notifyPackageInstalled(newPackage.mPackageInfo, mUser0);
253 notifyDexLoad(mFooUser0, newSecondaries, mUser0);
254
255 // We should get back the right info.
256 PackageUseInfo pui = getPackageUseInfo(newPackage);
Calin Juravle52a452c2017-08-04 01:42:17 -0700257 assertIsUsedByOtherApps(newPackage, pui, false);
Calin Juravle0d4b8f82017-01-23 23:34:25 -0800258 assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size());
259 assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/true, mUser0);
260 }
261
262 @Test
263 public void testNotifyPackageInstallSelfUse() {
264 TestData newPackage = new TestData("newPackage",
265 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0);
266
267 List<String> newSecondaries = newPackage.getSecondaryDexPaths();
268 // Packages should be able to find their own dex files even if the notification about
269 // their installation is delayed.
270 notifyDexLoad(newPackage, newSecondaries, mUser0);
271
272 PackageUseInfo pui = getPackageUseInfo(newPackage);
Calin Juravle52a452c2017-08-04 01:42:17 -0700273 assertIsUsedByOtherApps(newPackage, pui, false);
Calin Juravle0d4b8f82017-01-23 23:34:25 -0800274 assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size());
275 assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/false, mUser0);
276 }
277
Calin Juravle99dd37b2017-02-22 19:05:06 -0800278 @Test
279 public void testNotifyPackageUpdated() {
280 // Foo loads Bar main apks.
281 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0);
282
283 // Bar is used by others now and should be in our records.
284 PackageUseInfo pui = getPackageUseInfo(mBarUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700285 assertIsUsedByOtherApps(mBarUser0, pui, true);
Calin Juravle99dd37b2017-02-22 19:05:06 -0800286 assertTrue(pui.getDexUseInfoMap().isEmpty());
287
288 // Notify that bar is updated.
289 mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(),
290 mBarUser0.mPackageInfo.applicationInfo.sourceDir,
291 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs);
292
293 // The usedByOtherApps flag should be clear now.
294 pui = getPackageUseInfo(mBarUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700295 assertIsUsedByOtherApps(mBarUser0, pui, false);
Calin Juravle99dd37b2017-02-22 19:05:06 -0800296 }
297
298 @Test
299 public void testNotifyPackageUpdatedCodeLocations() {
300 // Simulate a split update.
301 String newSplit = mBarUser0.replaceLastSplit();
302 List<String> newSplits = new ArrayList<>();
303 newSplits.add(newSplit);
304
305 // We shouldn't find yet the new split as we didn't notify the package update.
306 notifyDexLoad(mFooUser0, newSplits, mUser0);
Calin Juravle3b74c412017-08-03 19:48:37 -0700307 assertNoUseInfo(mBarUser0);
Calin Juravle99dd37b2017-02-22 19:05:06 -0800308
309 // Notify that bar is updated. splitSourceDirs will contain the updated path.
310 mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(),
311 mBarUser0.mPackageInfo.applicationInfo.sourceDir,
312 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs);
313
314 // Now, when the split is loaded we will find it and we should mark Bar as usedByOthers.
315 notifyDexLoad(mFooUser0, newSplits, mUser0);
Calin Juravle3b74c412017-08-03 19:48:37 -0700316 PackageUseInfo pui = getPackageUseInfo(mBarUser0);
Calin Juravle99dd37b2017-02-22 19:05:06 -0800317 assertNotNull(pui);
Calin Juravle52a452c2017-08-04 01:42:17 -0700318 assertIsUsedByOtherApps(newSplits, pui, true);
Calin Juravle99dd37b2017-02-22 19:05:06 -0800319 }
320
321 @Test
322 public void testNotifyPackageDataDestroyForOne() {
323 // Bar loads its own secondary files.
324 notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0);
325 notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1);
326
327 mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0);
328
329 // Bar should not be around since it was removed for all users.
330 PackageUseInfo pui = getPackageUseInfo(mBarUser1);
331 assertNotNull(pui);
332 assertSecondaryUse(mBarUser1, pui, mBarUser1.getSecondaryDexPaths(),
333 /*isUsedByOtherApps*/false, mUser1);
334 }
335
336 @Test
337 public void testNotifyPackageDataDestroyForeignUse() {
338 // Foo loads its own secondary files.
339 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
340 notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
341
342 // Bar loads Foo main apks.
343 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0);
344
345 mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
346
347 // Foo should still be around since it's used by other apps but with no
348 // secondary dex info.
349 PackageUseInfo pui = getPackageUseInfo(mFooUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700350 assertIsUsedByOtherApps(mFooUser0, pui, true);
Calin Juravle99dd37b2017-02-22 19:05:06 -0800351 assertTrue(pui.getDexUseInfoMap().isEmpty());
352 }
353
354 @Test
355 public void testNotifyPackageDataDestroyComplete() {
356 // Foo loads its own secondary files.
357 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths();
358 notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
359
360 mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0);
361
362 // Foo should not be around since all its secondary dex info were deleted
363 // and it is not used by other apps.
Calin Juravle3b74c412017-08-03 19:48:37 -0700364 assertNoUseInfo(mFooUser0);
Calin Juravle99dd37b2017-02-22 19:05:06 -0800365 }
366
367 @Test
368 public void testNotifyPackageDataDestroyForAll() {
369 // Foo loads its own secondary files.
370 notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0);
371 notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1);
372
373 mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), UserHandle.USER_ALL);
374
375 // Bar should not be around since it was removed for all users.
Calin Juravle3b74c412017-08-03 19:48:37 -0700376 assertNoUseInfo(mBarUser0);
Calin Juravle99dd37b2017-02-22 19:05:06 -0800377 }
378
Calin Juravle2dfc1b32017-03-10 18:24:33 -0800379 @Test
380 public void testNotifyFrameworkLoad() {
381 String frameworkDex = "/system/framework/com.android.location.provider.jar";
382 // Load a dex file from framework.
383 notifyDexLoad(mFooUser0, Arrays.asList(frameworkDex), mUser0);
384 // The dex file should not be recognized as a package.
Calin Juravle3b74c412017-08-03 19:48:37 -0700385 assertFalse(mDexManager.hasInfoOnPackage(frameworkDex));
Calin Juravle2dfc1b32017-03-10 18:24:33 -0800386 }
387
Calin Juravleadbadd52017-03-28 18:19:15 -0700388 @Test
389 public void testNotifySecondaryFromProtected() {
390 // Foo loads its own secondary files.
391 List<String> fooSecondaries = mFooUser0.getSecondaryDexPathsFromProtectedDirs();
392 notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
393
394 PackageUseInfo pui = getPackageUseInfo(mFooUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700395 assertIsUsedByOtherApps(mFooUser0, pui, false);
Calin Juravleadbadd52017-03-28 18:19:15 -0700396 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size());
397 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0);
398 }
399
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700400 @Test
401 public void testNotifyUnsupportedClassLoader() {
402 List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths();
403 notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0);
404
Alan Stokes6dba50d2018-10-30 15:05:36 +0000405 assertNoUseInfo(mBarUser0UnsupportedClassLoader);
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700406 }
407
408 @Test
Alan Stokesb6c3a602018-11-02 12:10:42 +0000409 public void testNotifySupportedAndUnsupportedClassLoader() {
410 String classPath = String.join(File.pathSeparator, mBarUser0.getSecondaryDexPaths());
411 List<String> classLoaders =
412 Arrays.asList(PATH_CLASS_LOADER_NAME, UNSUPPORTED_CLASS_LOADER_NAME);
413 List<String> classPaths = Arrays.asList(classPath, classPath);
414 notifyDexLoad(mBarUser0, classLoaders, classPaths, mUser0);
415
416 assertNoUseInfo(mBarUser0);
417 }
418
419 @Test
420 public void testNotifyNullClassPath() {
421 notifyDexLoad(mBarUser0, null, mUser0);
422
423 assertNoUseInfo(mBarUser0);
424 }
425
426 @Test
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700427 public void testNotifyVariableClassLoader() {
428 // Record bar secondaries with the default PathClassLoader.
429 List<String> secondaries = mBarUser0.getSecondaryDexPaths();
430
431 notifyDexLoad(mBarUser0, secondaries, mUser0);
432 PackageUseInfo pui = getPackageUseInfo(mBarUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700433 assertIsUsedByOtherApps(mBarUser0, pui, false);
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700434 assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
435 assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
436
437 // Record bar secondaries again with a different class loader. This will change the context.
438 notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0);
439
440 pui = getPackageUseInfo(mBarUser0);
Calin Juravle52a452c2017-08-04 01:42:17 -0700441 assertIsUsedByOtherApps(mBarUser0, pui, false);
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700442 assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
443 // We expect that all the contexts to be changed to variable now.
444 String[] expectedContexts =
445 Collections.nCopies(secondaries.size(),
446 PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT).toArray(new String[0]);
447 assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0,
448 expectedContexts);
449 }
450
451 @Test
Alan Stokes6dba50d2018-10-30 15:05:36 +0000452 public void testNotifyUnsupportedClassLoaderDoesNotChangeExisting() {
453 List<String> secondaries = mBarUser0.getSecondaryDexPaths();
454
455 notifyDexLoad(mBarUser0, secondaries, mUser0);
456 PackageUseInfo pui = getPackageUseInfo(mBarUser0);
457 assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
458
459 // Record bar secondaries again with an unsupported class loader. This should not change the
460 // context.
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700461 notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0);
Alan Stokes6dba50d2018-10-30 15:05:36 +0000462 pui = getPackageUseInfo(mBarUser0);
463 assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700464 }
465
Alan Stokesa0023602017-10-16 12:31:44 +0100466 @Test
467 public void testReconcileSecondaryDexFiles_invokesListener() throws Exception {
468 List<String> fooSecondaries = mFooUser0.getSecondaryDexPathsFromProtectedDirs();
469 notifyDexLoad(mFooUser0, fooSecondaries, mUser0);
470
471 when(mPM.getPackageInfo(mFooUser0.getPackageName(), 0, 0))
472 .thenReturn(mFooUser0.mPackageInfo);
473
474 mDexManager.reconcileSecondaryDexFiles(mFooUser0.getPackageName());
475
476 verify(mListener, times(fooSecondaries.size()))
477 .onReconcileSecondaryDexFile(any(ApplicationInfo.class),
478 any(DexUseInfo.class), anyString(), anyInt());
479 }
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700480
Calin Juravleb8976d82016-12-16 16:22:00 +0000481 private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700482 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId,
483 String[] expectedContexts) {
484 assertNotNull(expectedContexts);
485 assertEquals(expectedContexts.length, secondaries.size());
486 int index = 0;
Calin Juravleb8976d82016-12-16 16:22:00 +0000487 for (String dex : secondaries) {
488 DexUseInfo dui = pui.getDexUseInfoMap().get(dex);
489 assertNotNull(dui);
490 assertEquals(isUsedByOtherApps, dui.isUsedByOtherApps());
491 assertEquals(ownerUserId, dui.getOwnerUserId());
492 assertEquals(1, dui.getLoaderIsas().size());
493 assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa));
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700494 assertEquals(expectedContexts[index++], dui.getClassLoaderContext());
Calin Juravleb8976d82016-12-16 16:22:00 +0000495 }
496 }
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700497 private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
498 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) {
499 String[] expectedContexts = DexoptUtils.processContextForDexLoad(
500 Arrays.asList(testData.mClassLoader),
501 Arrays.asList(String.join(File.pathSeparator, secondaries)));
502 assertSecondaryUse(testData, pui, secondaries, isUsedByOtherApps, ownerUserId,
503 expectedContexts);
504 }
Calin Juravleb8976d82016-12-16 16:22:00 +0000505
Calin Juravle52a452c2017-08-04 01:42:17 -0700506 private void assertIsUsedByOtherApps(TestData testData, PackageUseInfo pui,
507 boolean isUsedByOtherApps) {
508 assertIsUsedByOtherApps(testData.getBaseAndSplitDexPaths(), pui, isUsedByOtherApps);
509 }
510
511 private void assertIsUsedByOtherApps(List<String> codePaths, PackageUseInfo pui,
512 boolean isUsedByOtherApps) {
513 for (String codePath : codePaths) {
514 assertEquals(codePath, isUsedByOtherApps, pui.isUsedByOtherApps(codePath));
515 }
516 }
Calin Juravleb8976d82016-12-16 16:22:00 +0000517 private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) {
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700518 // By default, assume a single class loader in the chain.
519 // This makes writing tests much easier.
520 List<String> classLoaders = Arrays.asList(testData.mClassLoader);
Alan Stokesb6c3a602018-11-02 12:10:42 +0000521 List<String> classPaths = (dexPaths == null)
522 ? Arrays.asList((String) null)
523 : Arrays.asList(String.join(File.pathSeparator, dexPaths));
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700524 notifyDexLoad(testData, classLoaders, classPaths, loaderUserId);
525 }
526
Alan Stokesb6c3a602018-11-02 12:10:42 +0000527 private void notifyDexLoad(TestData testData, List<String> classLoaders,
528 List<String> classPaths, int loaderUserId) {
529 // We call the internal function so any exceptions thrown cause test failures.
530 mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, classLoaders,
531 classPaths, testData.mLoaderIsa, loaderUserId);
Calin Juravleb8976d82016-12-16 16:22:00 +0000532 }
533
534 private PackageUseInfo getPackageUseInfo(TestData testData) {
Alan Stokesa0023602017-10-16 12:31:44 +0100535 assertTrue(mDexManager.hasInfoOnPackage(testData.getPackageName()));
536 return mDexManager.getPackageUseInfoOrDefault(testData.getPackageName());
Calin Juravle3b74c412017-08-03 19:48:37 -0700537 }
538
539 private void assertNoUseInfo(TestData testData) {
Alan Stokesa0023602017-10-16 12:31:44 +0100540 assertFalse(mDexManager.hasInfoOnPackage(testData.getPackageName()));
Calin Juravleb8976d82016-12-16 16:22:00 +0000541 }
542
543 private static PackageInfo getMockPackageInfo(String packageName, int userId) {
544 PackageInfo pi = new PackageInfo();
545 pi.packageName = packageName;
546 pi.applicationInfo = getMockApplicationInfo(packageName, userId);
547 return pi;
548 }
549
550 private static ApplicationInfo getMockApplicationInfo(String packageName, int userId) {
551 ApplicationInfo ai = new ApplicationInfo();
552 String codeDir = "/data/app/" + packageName;
553 ai.setBaseCodePath(codeDir + "/base.dex");
554 ai.setSplitCodePaths(new String[] {codeDir + "/split-1.dex", codeDir + "/split-2.dex"});
555 ai.dataDir = "/data/user/" + userId + "/" + packageName;
Calin Juravleadbadd52017-03-28 18:19:15 -0700556 ai.deviceProtectedDataDir = "/data/user_de/" + userId + "/" + packageName;
557 ai.credentialProtectedDataDir = "/data/user_ce/" + userId + "/" + packageName;
Calin Juravleb8976d82016-12-16 16:22:00 +0000558 ai.packageName = packageName;
559 return ai;
560 }
561
562 private static class TestData {
563 private final PackageInfo mPackageInfo;
564 private final String mLoaderIsa;
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700565 private final String mClassLoader;
Calin Juravleb8976d82016-12-16 16:22:00 +0000566
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700567 private TestData(String packageName, String loaderIsa, int userId, String classLoader) {
Calin Juravleb8976d82016-12-16 16:22:00 +0000568 mPackageInfo = getMockPackageInfo(packageName, userId);
569 mLoaderIsa = loaderIsa;
Calin Juravlef1ff36f2017-07-22 12:33:41 -0700570 mClassLoader = classLoader;
571 }
572
573 private TestData(String packageName, String loaderIsa, int userId) {
574 this(packageName, loaderIsa, userId, PATH_CLASS_LOADER_NAME);
Calin Juravleb8976d82016-12-16 16:22:00 +0000575 }
576
577 private String getPackageName() {
578 return mPackageInfo.packageName;
579 }
580
581 List<String> getSecondaryDexPaths() {
582 List<String> paths = new ArrayList<>();
583 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary1.dex");
584 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary2.dex");
585 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary3.dex");
586 return paths;
587 }
588
589 List<String> getSecondaryDexPathsForOwnUse() {
590 List<String> paths = new ArrayList<>();
591 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary4.dex");
592 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary5.dex");
593 return paths;
594 }
595
Calin Juravleadbadd52017-03-28 18:19:15 -0700596 List<String> getSecondaryDexPathsFromProtectedDirs() {
597 List<String> paths = new ArrayList<>();
Alan Stokesa0023602017-10-16 12:31:44 +0100598 paths.add(mPackageInfo.applicationInfo.deviceProtectedDataDir + "/secondary6.dex");
599 paths.add(mPackageInfo.applicationInfo.credentialProtectedDataDir + "/secondary7.dex");
Calin Juravleadbadd52017-03-28 18:19:15 -0700600 return paths;
601 }
602
Calin Juravleb8976d82016-12-16 16:22:00 +0000603 List<String> getBaseAndSplitDexPaths() {
604 List<String> paths = new ArrayList<>();
605 paths.add(mPackageInfo.applicationInfo.sourceDir);
606 for (String split : mPackageInfo.applicationInfo.splitSourceDirs) {
607 paths.add(split);
608 }
609 return paths;
610 }
Calin Juravle99dd37b2017-02-22 19:05:06 -0800611
612 String replaceLastSplit() {
613 int length = mPackageInfo.applicationInfo.splitSourceDirs.length;
614 // Add an extra bogus dex extension to simulate a new split name.
615 mPackageInfo.applicationInfo.splitSourceDirs[length - 1] += ".dex";
616 return mPackageInfo.applicationInfo.splitSourceDirs[length - 1];
617 }
Calin Juravleb8976d82016-12-16 16:22:00 +0000618 }
619}