blob: b655f3af3a24306e902da512038f0cde3488b428 [file] [log] [blame]
Calin Juravle5a9094c2016-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
19import android.os.Build;
20import android.content.pm.ApplicationInfo;
21import android.content.pm.PackageInfo;
22import android.support.test.filters.SmallTest;
23import android.support.test.runner.AndroidJUnit4;
24
25import dalvik.system.VMRuntime;
26
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.HashMap;
30import java.util.List;
31import java.util.Map;
32
33import org.junit.Before;
34import org.junit.Test;
35import org.junit.runner.RunWith;
36
37import static org.junit.Assert.assertEquals;
38import static org.junit.Assert.assertFalse;
39import static org.junit.Assert.assertNotNull;
40import static org.junit.Assert.assertNull;
41import static org.junit.Assert.assertTrue;
42import static org.junit.Assert.fail;
43
44import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
45import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
46
47@RunWith(AndroidJUnit4.class)
48@SmallTest
49public class DexManagerTests {
50 private DexManager mDexManager;
51
52 private TestData mFooUser0;
53 private TestData mBarUser0;
54 private TestData mBarUser1;
55 private TestData mInvalidIsa;
56 private TestData mDoesNotExist;
57
58 private int mUser0;
59 private int mUser1;
60 @Before
61 public void setup() {
62
63 mUser0 = 0;
64 mUser1 = 1;
65
66 String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
67 String foo = "foo";
68 String bar = "bar";
69
70 mFooUser0 = new TestData(foo, isa, mUser0);
71 mBarUser0 = new TestData(bar, isa, mUser0);
72 mBarUser1 = new TestData(bar, isa, mUser1);
73 mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0);
74 mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1);
75
76
77 mDexManager = new DexManager();
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 private void assertSecondaryUse(TestData testData, PackageUseInfo pui,
208 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) {
209 for (String dex : secondaries) {
210 DexUseInfo dui = pui.getDexUseInfoMap().get(dex);
211 assertNotNull(dui);
212 assertEquals(isUsedByOtherApps, dui.isUsedByOtherApps());
213 assertEquals(ownerUserId, dui.getOwnerUserId());
214 assertEquals(1, dui.getLoaderIsas().size());
215 assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa));
216 }
217 }
218
219 private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) {
220 mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, dexPaths,
221 testData.mLoaderIsa, loaderUserId);
222 }
223
224 private PackageUseInfo getPackageUseInfo(TestData testData) {
225 return mDexManager.getPackageUseInfo(testData.mPackageInfo.packageName);
226 }
227
228 private static PackageInfo getMockPackageInfo(String packageName, int userId) {
229 PackageInfo pi = new PackageInfo();
230 pi.packageName = packageName;
231 pi.applicationInfo = getMockApplicationInfo(packageName, userId);
232 return pi;
233 }
234
235 private static ApplicationInfo getMockApplicationInfo(String packageName, int userId) {
236 ApplicationInfo ai = new ApplicationInfo();
237 String codeDir = "/data/app/" + packageName;
238 ai.setBaseCodePath(codeDir + "/base.dex");
239 ai.setSplitCodePaths(new String[] {codeDir + "/split-1.dex", codeDir + "/split-2.dex"});
240 ai.dataDir = "/data/user/" + userId + "/" + packageName;
241 ai.packageName = packageName;
242 return ai;
243 }
244
245 private static class TestData {
246 private final PackageInfo mPackageInfo;
247 private final String mLoaderIsa;
248
249 private TestData(String packageName, String loaderIsa, int userId) {
250 mPackageInfo = getMockPackageInfo(packageName, userId);
251 mLoaderIsa = loaderIsa;
252 }
253
254 private String getPackageName() {
255 return mPackageInfo.packageName;
256 }
257
258 List<String> getSecondaryDexPaths() {
259 List<String> paths = new ArrayList<>();
260 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary1.dex");
261 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary2.dex");
262 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary3.dex");
263 return paths;
264 }
265
266 List<String> getSecondaryDexPathsForOwnUse() {
267 List<String> paths = new ArrayList<>();
268 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary4.dex");
269 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary5.dex");
270 return paths;
271 }
272
273 List<String> getBaseAndSplitDexPaths() {
274 List<String> paths = new ArrayList<>();
275 paths.add(mPackageInfo.applicationInfo.sourceDir);
276 for (String split : mPackageInfo.applicationInfo.splitSourceDirs) {
277 paths.add(split);
278 }
279 return paths;
280 }
281 }
282}