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