1/*
2 * Copyright (C) 2012 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;
18
19import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
20import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
21import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
22import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
23
24import android.annotation.NonNull;
25import android.content.Context;
26import android.content.pm.PackageParser;
27import android.content.pm.UserInfo;
28import android.os.UserHandle;
29import android.test.AndroidTestCase;
30import android.util.ArrayMap;
31import android.util.ArraySet;
32import android.util.Log;
33import android.util.LongSparseArray;
34
35import com.android.internal.os.AtomicFile;
36
37import java.lang.reflect.Constructor;
38import java.io.File;
39import java.io.FileOutputStream;
40import java.io.IOException;
41import java.security.PublicKey;
42import java.util.ArrayList;
43import java.util.List;
44
45public class PackageManagerSettingsTests extends AndroidTestCase {
46    private static final String PACKAGE_NAME_2 = "com.google.app2";
47    private static final String PACKAGE_NAME_3 = "com.android.app3";
48    private static final String PACKAGE_NAME_1 = "com.google.app1";
49    private static final boolean localLOGV = true;
50    public static final String TAG = "PackageManagerSettingsTests";
51    protected final String PREFIX = "android.content.pm";
52
53    private @NonNull List<UserInfo> createFakeUsers() {
54        ArrayList<UserInfo> users = new ArrayList<>();
55        users.add(new UserInfo(UserHandle.USER_SYSTEM, "test user", UserInfo.FLAG_INITIALIZED));
56        return users;
57    }
58
59    private void writeFile(File file, byte[] data) {
60        file.mkdirs();
61        try {
62            AtomicFile aFile = new AtomicFile(file);
63            FileOutputStream fos = aFile.startWrite();
64            fos.write(data);
65            aFile.finishWrite(fos);
66        } catch (IOException ioe) {
67            Log.e(TAG, "Cannot write file " + file.getPath());
68        }
69    }
70
71    private void writePackagesXml() {
72        writeFile(new File(getContext().getFilesDir(), "system/packages.xml"),
73                ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
74                + "<packages>"
75                + "<last-platform-version internal=\"15\" external=\"0\" fingerprint=\"foo\" />"
76                + "<permission-trees>"
77                + "<item name=\"com.google.android.permtree\" package=\"com.google.android.permpackage\" />"
78                + "</permission-trees>"
79                + "<permissions>"
80                + "<item name=\"android.permission.WRITE_CALL_LOG\" package=\"android\" protection=\"1\" />"
81                + "<item name=\"android.permission.ASEC_ACCESS\" package=\"android\" protection=\"2\" />"
82                + "<item name=\"android.permission.ACCESS_WIMAX_STATE\" package=\"android\" />"
83                + "<item name=\"android.permission.REBOOT\" package=\"android\" protection=\"18\" />"
84                + "</permissions>"
85                + "<package name=\"com.google.app1\" codePath=\"/system/app/app1.apk\" nativeLibraryPath=\"/data/data/com.google.app1/lib\" flags=\"1\" ft=\"1360e2caa70\" it=\"135f2f80d08\" ut=\"1360e2caa70\" version=\"1109\" sharedUserId=\"11000\">"
86                + "<sigs count=\"1\">"
87                + "<cert index=\"0\" key=\"" + KeySetStrings.ctsKeySetCertA + "\" />"
88                + "</sigs>"
89                + "<proper-signing-keyset identifier=\"1\" />"
90                + "</package>"
91                + "<package name=\"com.google.app2\" codePath=\"/system/app/app2.apk\" nativeLibraryPath=\"/data/data/com.google.app2/lib\" flags=\"1\" ft=\"1360e578718\" it=\"135f2f80d08\" ut=\"1360e578718\" version=\"15\" enabled=\"3\" userId=\"11001\">"
92                + "<sigs count=\"1\">"
93                + "<cert index=\"0\" />"
94                + "</sigs>"
95                + "<proper-signing-keyset identifier=\"1\" />"
96                + "<defined-keyset alias=\"AB\" identifier=\"4\" />"
97                + "</package>"
98                + "<package name=\"com.android.app3\" codePath=\"/system/app/app3.apk\" nativeLibraryPath=\"/data/data/com.android.app3/lib\" flags=\"1\" ft=\"1360e577b60\" it=\"135f2f80d08\" ut=\"1360e577b60\" version=\"15\" userId=\"11030\">"
99                + "<sigs count=\"1\">"
100                + "<cert index=\"1\" key=\"" + KeySetStrings.ctsKeySetCertB + "\" />"
101                + "</sigs>"
102                + "<proper-signing-keyset identifier=\"2\" />"
103                + "<upgrade-keyset identifier=\"3\" />"
104                + "<defined-keyset alias=\"C\" identifier=\"3\" />"
105                + "</package>"
106                + "<shared-user name=\"com.android.shared1\" userId=\"11000\">"
107                + "<sigs count=\"1\">"
108                + "<cert index=\"1\" />"
109                + "</sigs>"
110                + "<perms>"
111                + "<item name=\"android.permission.REBOOT\" />"
112                + "</perms>"
113                + "</shared-user>"
114                + "<keyset-settings version=\"1\">"
115                + "<keys>"
116                + "<public-key identifier=\"1\" value=\"" + KeySetStrings.ctsKeySetPublicKeyA + "\" />"
117                + "<public-key identifier=\"2\" value=\"" + KeySetStrings.ctsKeySetPublicKeyB + "\" />"
118                + "<public-key identifier=\"3\" value=\"" + KeySetStrings.ctsKeySetPublicKeyC + "\" />"
119                + "</keys>"
120                + "<keysets>"
121                + "<keyset identifier=\"1\">"
122                + "<key-id identifier=\"1\" />"
123                + "</keyset>"
124                + "<keyset identifier=\"2\">"
125                + "<key-id identifier=\"2\" />"
126                + "</keyset>"
127                + "<keyset identifier=\"3\">"
128                + "<key-id identifier=\"3\" />"
129                + "</keyset>"
130                + "<keyset identifier=\"4\">"
131                + "<key-id identifier=\"1\" />"
132                + "<key-id identifier=\"2\" />"
133                + "</keyset>"
134                + "</keysets>"
135                + "<lastIssuedKeyId value=\"3\" />"
136                + "<lastIssuedKeySetId value=\"4\" />"
137                + "</keyset-settings>"
138                + "</packages>").getBytes());
139    }
140
141    private void writeStoppedPackagesXml() {
142        writeFile(new File(getContext().getFilesDir(), "system/packages-stopped.xml"),
143                ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
144                + "<stopped-packages>"
145                + "<pkg name=\"com.google.app1\" nl=\"1\" />"
146                + "<pkg name=\"com.android.app3\" nl=\"1\" />"
147                + "</stopped-packages>")
148                .getBytes());
149    }
150
151    private void writePackagesList() {
152        writeFile(new File(getContext().getFilesDir(), "system/packages.list"),
153                ( "com.google.app1 11000 0 /data/data/com.google.app1 seinfo1"
154                + "com.google.app2 11001 0 /data/data/com.google.app2 seinfo2"
155                + "com.android.app3 11030 0 /data/data/com.android.app3 seinfo3")
156                .getBytes());
157    }
158
159    private void deleteSystemFolder() {
160        File systemFolder = new File(getContext().getFilesDir(), "system");
161        deleteFolder(systemFolder);
162    }
163
164    private static void deleteFolder(File folder) {
165        File[] files = folder.listFiles();
166        if (files != null) {
167            for (File file : files) {
168                deleteFolder(file);
169            }
170        }
171        folder.delete();
172    }
173
174    private void writeOldFiles() {
175        deleteSystemFolder();
176        writePackagesXml();
177        writeStoppedPackagesXml();
178        writePackagesList();
179    }
180
181    private void createUserManagerServiceRef() throws ReflectiveOperationException {
182        Constructor<UserManagerService> umsc =
183                UserManagerService.class.getDeclaredConstructor(
184                        Context.class,
185                        PackageManagerService.class,
186                        Object.class,
187                        Object.class,
188                        File.class,
189                        File.class);
190        umsc.setAccessible(true);
191        UserManagerService ums = umsc.newInstance(getContext(), null,
192                new Object(), new Object(), getContext().getFilesDir(),
193                new File(getContext().getFilesDir(), "user"));
194    }
195
196    private void verifyKeySetMetaData(Settings settings)
197            throws ReflectiveOperationException, IllegalAccessException {
198        ArrayMap<String, PackageSetting> packages = settings.mPackages;
199        KeySetManagerService ksms = settings.mKeySetManagerService;
200
201        /* verify keyset and public key ref counts */
202        assertEquals(2, KeySetUtils.getKeySetRefCount(ksms, 1));
203        assertEquals(1, KeySetUtils.getKeySetRefCount(ksms, 2));
204        assertEquals(1, KeySetUtils.getKeySetRefCount(ksms, 3));
205        assertEquals(1, KeySetUtils.getKeySetRefCount(ksms, 4));
206        assertEquals(2, KeySetUtils.getPubKeyRefCount(ksms, 1));
207        assertEquals(2, KeySetUtils.getPubKeyRefCount(ksms, 2));
208        assertEquals(1, KeySetUtils.getPubKeyRefCount(ksms, 3));
209
210        /* verify public keys properly read */
211        PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA);
212        PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB);
213        PublicKey keyC = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyC);
214        assertEquals(keyA, KeySetUtils.getPubKey(ksms, 1));
215        assertEquals(keyB, KeySetUtils.getPubKey(ksms, 2));
216        assertEquals(keyC, KeySetUtils.getPubKey(ksms, 3));
217
218        /* verify mapping is correct (ks -> pub keys) */
219        LongSparseArray<ArraySet<Long>> ksMapping = KeySetUtils.getKeySetMapping(ksms);
220        ArraySet<Long> mapping = ksMapping.get(1);
221        assertEquals(1, mapping.size());
222        assertTrue(mapping.contains(new Long(1)));
223        mapping = ksMapping.get(2);
224        assertEquals(1, mapping.size());
225        assertTrue(mapping.contains(new Long(2)));
226        mapping = ksMapping.get(3);
227        assertEquals(1, mapping.size());
228        assertTrue(mapping.contains(new Long(3)));
229        mapping = ksMapping.get(4);
230        assertEquals(2, mapping.size());
231        assertTrue(mapping.contains(new Long(1)));
232        assertTrue(mapping.contains(new Long(2)));
233
234        /* verify lastIssuedIds are consistent */
235        assertEquals(new Long(3), KeySetUtils.getLastIssuedKeyId(ksms));
236        assertEquals(new Long(4), KeySetUtils.getLastIssuedKeySetId(ksms));
237
238        /* verify packages have been given the appropriat information */
239        PackageSetting ps = packages.get("com.google.app1");
240        assertEquals(1, ps.keySetData.getProperSigningKeySet());
241        ps = packages.get("com.google.app2");
242        assertEquals(1, ps.keySetData.getProperSigningKeySet());
243        assertEquals(new Long(4), ps.keySetData.getAliases().get("AB"));
244        ps = packages.get("com.android.app3");
245        assertEquals(2, ps.keySetData.getProperSigningKeySet());
246        assertEquals(new Long(3), ps.keySetData.getAliases().get("C"));
247        assertEquals(1, ps.keySetData.getUpgradeKeySets().length);
248        assertEquals(3, ps.keySetData.getUpgradeKeySets()[0]);
249    }
250
251    /* make sure our initialized keysetmanagerservice metadata matches packages.xml */
252    public void testReadKeySetSettings()
253            throws ReflectiveOperationException, IllegalAccessException {
254
255        /* write out files and read */
256        writeOldFiles();
257        createUserManagerServiceRef();
258        Settings settings = new Settings(getContext().getFilesDir(), new Object());
259        assertEquals(true, settings.readLPw(createFakeUsers()));
260        verifyKeySetMetaData(settings);
261    }
262
263    /* read in data, write it out, and read it back in.  Verify same. */
264    public void testWriteKeySetSettings()
265            throws ReflectiveOperationException, IllegalAccessException {
266
267        /* write out files and read */
268        writeOldFiles();
269        createUserManagerServiceRef();
270        Settings settings = new Settings(getContext().getFilesDir(), new Object());
271        assertEquals(true, settings.readLPw(createFakeUsers()));
272
273        /* write out, read back in and verify the same */
274        settings.writeLPr();
275        assertEquals(true, settings.readLPw(createFakeUsers()));
276        verifyKeySetMetaData(settings);
277    }
278
279    public void testSettingsReadOld() {
280        // Write the package files and make sure they're parsed properly the first time
281        writeOldFiles();
282        Settings settings = new Settings(getContext().getFilesDir(), new Object());
283        assertEquals(true, settings.readLPw(createFakeUsers()));
284        assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_3));
285        assertNotNull(settings.peekPackageLPr(PACKAGE_NAME_1));
286
287        PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
288        assertEquals(COMPONENT_ENABLED_STATE_DEFAULT, ps.getEnabled(0));
289        assertEquals(true, ps.getNotLaunched(0));
290
291        ps = settings.peekPackageLPr(PACKAGE_NAME_2);
292        assertEquals(false, ps.getStopped(0));
293        assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
294        assertEquals(COMPONENT_ENABLED_STATE_DEFAULT, ps.getEnabled(1));
295    }
296
297    public void testNewPackageRestrictionsFile() throws ReflectiveOperationException {
298
299        // Write the package files and make sure they're parsed properly the first time
300        writeOldFiles();
301        createUserManagerServiceRef();
302        Settings settings = new Settings(getContext().getFilesDir(), new Object());
303        assertEquals(true, settings.readLPw(createFakeUsers()));
304        settings.writeLPr();
305
306        // Create Settings again to make it read from the new files
307        settings = new Settings(getContext().getFilesDir(), new Object());
308        assertEquals(true, settings.readLPw(createFakeUsers()));
309
310        PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
311        assertEquals(COMPONENT_ENABLED_STATE_DISABLED_USER, ps.getEnabled(0));
312        assertEquals(COMPONENT_ENABLED_STATE_DEFAULT, ps.getEnabled(1));
313    }
314
315    public void testEnableDisable() {
316        // Write the package files and make sure they're parsed properly the first time
317        writeOldFiles();
318        Settings settings = new Settings(getContext().getFilesDir(), new Object());
319        assertEquals(true, settings.readLPw(createFakeUsers()));
320
321        // Enable/Disable a package
322        PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
323        ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
324        ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1, null);
325        assertEquals(COMPONENT_ENABLED_STATE_DISABLED, ps.getEnabled(0));
326        assertEquals(COMPONENT_ENABLED_STATE_ENABLED, ps.getEnabled(1));
327
328        // Enable/Disable a component
329        ArraySet<String> components = new ArraySet<String>();
330        String component1 = PACKAGE_NAME_1 + "/.Component1";
331        components.add(component1);
332        ps.setDisabledComponents(components, 0);
333        ArraySet<String> componentsDisabled = ps.getDisabledComponents(0);
334        assertEquals(1, componentsDisabled.size());
335        assertEquals(component1, componentsDisabled.toArray()[0]);
336        boolean hasEnabled =
337                ps.getEnabledComponents(0) != null && ps.getEnabledComponents(1).size() > 0;
338        assertEquals(false, hasEnabled);
339
340        // User 1 should not have any disabled components
341        boolean hasDisabled =
342                ps.getDisabledComponents(1) != null && ps.getDisabledComponents(1).size() > 0;
343        assertEquals(false, hasDisabled);
344        ps.setEnabledComponents(components, 1);
345        assertEquals(1, ps.getEnabledComponents(1).size());
346        hasEnabled = ps.getEnabledComponents(0) != null && ps.getEnabledComponents(0).size() > 0;
347        assertEquals(false, hasEnabled);
348    }
349}
350