1 /* 2 * Copyright (C) 2014 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; 18 19 import static com.android.internal.util.ArrayUtils.appendInt; 20 21 import android.app.ActivityManager; 22 import android.content.ComponentName; 23 import android.content.pm.FeatureInfo; 24 import android.content.pm.PackageManager; 25 import android.os.Environment; 26 import android.os.Process; 27 import android.os.storage.StorageManager; 28 import android.text.TextUtils; 29 import android.util.ArrayMap; 30 import android.util.ArraySet; 31 import android.util.Slog; 32 import android.util.SparseArray; 33 import android.util.Xml; 34 35 import com.android.internal.util.XmlUtils; 36 37 import libcore.io.IoUtils; 38 39 import org.xmlpull.v1.XmlPullParser; 40 import org.xmlpull.v1.XmlPullParserException; 41 42 import java.io.File; 43 import java.io.FileNotFoundException; 44 import java.io.FileReader; 45 import java.io.IOException; 46 import java.util.ArrayList; 47 import java.util.List; 48 49 /** 50 * Loads global system configuration info. 51 */ 52 public class SystemConfig { 53 static final String TAG = "SystemConfig"; 54 55 static SystemConfig sInstance; 56 57 // permission flag, determines which types of configuration are allowed to be read 58 private static final int ALLOW_FEATURES = 0x01; 59 private static final int ALLOW_LIBS = 0x02; 60 private static final int ALLOW_PERMISSIONS = 0x04; 61 private static final int ALLOW_APP_CONFIGS = 0x08; 62 private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10; 63 private static final int ALLOW_ALL = ~0; 64 65 // Group-ids that are given to all packages as read from etc/permissions/*.xml. 66 int[] mGlobalGids; 67 68 // These are the built-in uid -> permission mappings that were read from the 69 // system configuration files. 70 final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>(); 71 72 // These are the built-in shared libraries that were read from the 73 // system configuration files. Keys are the library names; strings are the 74 // paths to the libraries. 75 final ArrayMap<String, String> mSharedLibraries = new ArrayMap<>(); 76 77 // These are the features this devices supports that were read from the 78 // system configuration files. 79 final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>(); 80 81 // These are the features which this device doesn't support; the OEM 82 // partition uses these to opt-out of features from the system image. 83 final ArraySet<String> mUnavailableFeatures = new ArraySet<>(); 84 85 public static final class PermissionEntry { 86 public final String name; 87 public int[] gids; 88 public boolean perUser; 89 PermissionEntry(String name, boolean perUser)90 PermissionEntry(String name, boolean perUser) { 91 this.name = name; 92 this.perUser = perUser; 93 } 94 } 95 96 // These are the permission -> gid mappings that were read from the 97 // system configuration files. 98 final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>(); 99 100 // These are the packages that are white-listed to be able to run in the 101 // background while in power save mode (but not whitelisted from device idle modes), 102 // as read from the configuration files. 103 final ArraySet<String> mAllowInPowerSaveExceptIdle = new ArraySet<>(); 104 105 // These are the packages that are white-listed to be able to run in the 106 // background while in power save mode, as read from the configuration files. 107 final ArraySet<String> mAllowInPowerSave = new ArraySet<>(); 108 109 // These are the packages that are white-listed to be able to run in the 110 // background while in data-usage save mode, as read from the configuration files. 111 final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>(); 112 113 // These are the packages that are white-listed to be able to run background location 114 // without throttling, as read from the configuration files. 115 final ArraySet<String> mAllowUnthrottledLocation = new ArraySet<>(); 116 117 // These are the action strings of broadcasts which are whitelisted to 118 // be delivered anonymously even to apps which target O+. 119 final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>(); 120 121 // These are the package names of apps which should be in the 'always' 122 // URL-handling state upon factory reset. 123 final ArraySet<String> mLinkedApps = new ArraySet<>(); 124 125 // These are the packages that are whitelisted to be able to run as system user 126 final ArraySet<String> mSystemUserWhitelistedApps = new ArraySet<>(); 127 128 // These are the packages that should not run under system user 129 final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>(); 130 131 // These are the components that are enabled by default as VR mode listener services. 132 final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>(); 133 134 // These are the permitted backup transport service components 135 final ArraySet<ComponentName> mBackupTransportWhitelist = new ArraySet<>(); 136 137 // These are the packages of carrier-associated apps which should be disabled until used until 138 // a SIM is inserted which grants carrier privileges to that carrier app. 139 final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps = 140 new ArrayMap<>(); 141 142 143 final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>(); 144 final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>(); 145 getInstance()146 public static SystemConfig getInstance() { 147 synchronized (SystemConfig.class) { 148 if (sInstance == null) { 149 sInstance = new SystemConfig(); 150 } 151 return sInstance; 152 } 153 } 154 getGlobalGids()155 public int[] getGlobalGids() { 156 return mGlobalGids; 157 } 158 getSystemPermissions()159 public SparseArray<ArraySet<String>> getSystemPermissions() { 160 return mSystemPermissions; 161 } 162 getSharedLibraries()163 public ArrayMap<String, String> getSharedLibraries() { 164 return mSharedLibraries; 165 } 166 getAvailableFeatures()167 public ArrayMap<String, FeatureInfo> getAvailableFeatures() { 168 return mAvailableFeatures; 169 } 170 getPermissions()171 public ArrayMap<String, PermissionEntry> getPermissions() { 172 return mPermissions; 173 } 174 getAllowImplicitBroadcasts()175 public ArraySet<String> getAllowImplicitBroadcasts() { 176 return mAllowImplicitBroadcasts; 177 } 178 getAllowInPowerSaveExceptIdle()179 public ArraySet<String> getAllowInPowerSaveExceptIdle() { 180 return mAllowInPowerSaveExceptIdle; 181 } 182 getAllowInPowerSave()183 public ArraySet<String> getAllowInPowerSave() { 184 return mAllowInPowerSave; 185 } 186 getAllowInDataUsageSave()187 public ArraySet<String> getAllowInDataUsageSave() { 188 return mAllowInDataUsageSave; 189 } 190 getAllowUnthrottledLocation()191 public ArraySet<String> getAllowUnthrottledLocation() { 192 return mAllowUnthrottledLocation; 193 } 194 getLinkedApps()195 public ArraySet<String> getLinkedApps() { 196 return mLinkedApps; 197 } 198 getSystemUserWhitelistedApps()199 public ArraySet<String> getSystemUserWhitelistedApps() { 200 return mSystemUserWhitelistedApps; 201 } 202 getSystemUserBlacklistedApps()203 public ArraySet<String> getSystemUserBlacklistedApps() { 204 return mSystemUserBlacklistedApps; 205 } 206 getDefaultVrComponents()207 public ArraySet<ComponentName> getDefaultVrComponents() { 208 return mDefaultVrComponents; 209 } 210 getBackupTransportWhitelist()211 public ArraySet<ComponentName> getBackupTransportWhitelist() { 212 return mBackupTransportWhitelist; 213 } 214 getDisabledUntilUsedPreinstalledCarrierAssociatedApps()215 public ArrayMap<String, List<String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps() { 216 return mDisabledUntilUsedPreinstalledCarrierAssociatedApps; 217 } 218 getPrivAppPermissions(String packageName)219 public ArraySet<String> getPrivAppPermissions(String packageName) { 220 return mPrivAppPermissions.get(packageName); 221 } 222 getPrivAppDenyPermissions(String packageName)223 public ArraySet<String> getPrivAppDenyPermissions(String packageName) { 224 return mPrivAppDenyPermissions.get(packageName); 225 } 226 SystemConfig()227 SystemConfig() { 228 // Read configuration from system 229 readPermissions(Environment.buildPath( 230 Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL); 231 // Read configuration from the old permissions dir 232 readPermissions(Environment.buildPath( 233 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL); 234 // Allow Vendor to customize system configs around libs, features, permissions and apps 235 int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS | 236 ALLOW_APP_CONFIGS; 237 readPermissions(Environment.buildPath( 238 Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag); 239 readPermissions(Environment.buildPath( 240 Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag); 241 // Allow ODM to customize system configs around libs, features and apps 242 int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS; 243 readPermissions(Environment.buildPath( 244 Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag); 245 readPermissions(Environment.buildPath( 246 Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag); 247 // Only allow OEM to customize features 248 readPermissions(Environment.buildPath( 249 Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES); 250 readPermissions(Environment.buildPath( 251 Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES); 252 } 253 readPermissions(File libraryDir, int permissionFlag)254 void readPermissions(File libraryDir, int permissionFlag) { 255 // Read permissions from given directory. 256 if (!libraryDir.exists() || !libraryDir.isDirectory()) { 257 if (permissionFlag == ALLOW_ALL) { 258 Slog.w(TAG, "No directory " + libraryDir + ", skipping"); 259 } 260 return; 261 } 262 if (!libraryDir.canRead()) { 263 Slog.w(TAG, "Directory " + libraryDir + " cannot be read"); 264 return; 265 } 266 267 // Iterate over the files in the directory and scan .xml files 268 File platformFile = null; 269 for (File f : libraryDir.listFiles()) { 270 // We'll read platform.xml last 271 if (f.getPath().endsWith("etc/permissions/platform.xml")) { 272 platformFile = f; 273 continue; 274 } 275 276 if (!f.getPath().endsWith(".xml")) { 277 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring"); 278 continue; 279 } 280 if (!f.canRead()) { 281 Slog.w(TAG, "Permissions library file " + f + " cannot be read"); 282 continue; 283 } 284 285 readPermissionsFromXml(f, permissionFlag); 286 } 287 288 // Read platform permissions last so it will take precedence 289 if (platformFile != null) { 290 readPermissionsFromXml(platformFile, permissionFlag); 291 } 292 } 293 readPermissionsFromXml(File permFile, int permissionFlag)294 private void readPermissionsFromXml(File permFile, int permissionFlag) { 295 FileReader permReader = null; 296 try { 297 permReader = new FileReader(permFile); 298 } catch (FileNotFoundException e) { 299 Slog.w(TAG, "Couldn't find or open permissions file " + permFile); 300 return; 301 } 302 303 final boolean lowRam = ActivityManager.isLowRamDeviceStatic(); 304 305 try { 306 XmlPullParser parser = Xml.newPullParser(); 307 parser.setInput(permReader); 308 309 int type; 310 while ((type=parser.next()) != parser.START_TAG 311 && type != parser.END_DOCUMENT) { 312 ; 313 } 314 315 if (type != parser.START_TAG) { 316 throw new XmlPullParserException("No start tag found"); 317 } 318 319 if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) { 320 throw new XmlPullParserException("Unexpected start tag in " + permFile 321 + ": found " + parser.getName() + ", expected 'permissions' or 'config'"); 322 } 323 324 boolean allowAll = permissionFlag == ALLOW_ALL; 325 boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0; 326 boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0; 327 boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0; 328 boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0; 329 boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0; 330 while (true) { 331 XmlUtils.nextElement(parser); 332 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { 333 break; 334 } 335 336 String name = parser.getName(); 337 if ("group".equals(name) && allowAll) { 338 String gidStr = parser.getAttributeValue(null, "gid"); 339 if (gidStr != null) { 340 int gid = android.os.Process.getGidForName(gidStr); 341 mGlobalGids = appendInt(mGlobalGids, gid); 342 } else { 343 Slog.w(TAG, "<group> without gid in " + permFile + " at " 344 + parser.getPositionDescription()); 345 } 346 347 XmlUtils.skipCurrentTag(parser); 348 continue; 349 } else if ("permission".equals(name) && allowPermissions) { 350 String perm = parser.getAttributeValue(null, "name"); 351 if (perm == null) { 352 Slog.w(TAG, "<permission> without name in " + permFile + " at " 353 + parser.getPositionDescription()); 354 XmlUtils.skipCurrentTag(parser); 355 continue; 356 } 357 perm = perm.intern(); 358 readPermission(parser, perm); 359 360 } else if ("assign-permission".equals(name) && allowPermissions) { 361 String perm = parser.getAttributeValue(null, "name"); 362 if (perm == null) { 363 Slog.w(TAG, "<assign-permission> without name in " + permFile + " at " 364 + parser.getPositionDescription()); 365 XmlUtils.skipCurrentTag(parser); 366 continue; 367 } 368 String uidStr = parser.getAttributeValue(null, "uid"); 369 if (uidStr == null) { 370 Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at " 371 + parser.getPositionDescription()); 372 XmlUtils.skipCurrentTag(parser); 373 continue; 374 } 375 int uid = Process.getUidForName(uidStr); 376 if (uid < 0) { 377 Slog.w(TAG, "<assign-permission> with unknown uid \"" 378 + uidStr + " in " + permFile + " at " 379 + parser.getPositionDescription()); 380 XmlUtils.skipCurrentTag(parser); 381 continue; 382 } 383 perm = perm.intern(); 384 ArraySet<String> perms = mSystemPermissions.get(uid); 385 if (perms == null) { 386 perms = new ArraySet<String>(); 387 mSystemPermissions.put(uid, perms); 388 } 389 perms.add(perm); 390 XmlUtils.skipCurrentTag(parser); 391 392 } else if ("library".equals(name) && allowLibs) { 393 String lname = parser.getAttributeValue(null, "name"); 394 String lfile = parser.getAttributeValue(null, "file"); 395 if (lname == null) { 396 Slog.w(TAG, "<library> without name in " + permFile + " at " 397 + parser.getPositionDescription()); 398 } else if (lfile == null) { 399 Slog.w(TAG, "<library> without file in " + permFile + " at " 400 + parser.getPositionDescription()); 401 } else { 402 //Log.i(TAG, "Got library " + lname + " in " + lfile); 403 mSharedLibraries.put(lname, lfile); 404 } 405 XmlUtils.skipCurrentTag(parser); 406 continue; 407 408 } else if ("feature".equals(name) && allowFeatures) { 409 String fname = parser.getAttributeValue(null, "name"); 410 int fversion = XmlUtils.readIntAttribute(parser, "version", 0); 411 boolean allowed; 412 if (!lowRam) { 413 allowed = true; 414 } else { 415 String notLowRam = parser.getAttributeValue(null, "notLowRam"); 416 allowed = !"true".equals(notLowRam); 417 } 418 if (fname == null) { 419 Slog.w(TAG, "<feature> without name in " + permFile + " at " 420 + parser.getPositionDescription()); 421 } else if (allowed) { 422 addFeature(fname, fversion); 423 } 424 XmlUtils.skipCurrentTag(parser); 425 continue; 426 427 } else if ("unavailable-feature".equals(name) && allowFeatures) { 428 String fname = parser.getAttributeValue(null, "name"); 429 if (fname == null) { 430 Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at " 431 + parser.getPositionDescription()); 432 } else { 433 mUnavailableFeatures.add(fname); 434 } 435 XmlUtils.skipCurrentTag(parser); 436 continue; 437 438 } else if ("allow-in-power-save-except-idle".equals(name) && allowAll) { 439 String pkgname = parser.getAttributeValue(null, "package"); 440 if (pkgname == null) { 441 Slog.w(TAG, "<allow-in-power-save-except-idle> without package in " 442 + permFile + " at " + parser.getPositionDescription()); 443 } else { 444 mAllowInPowerSaveExceptIdle.add(pkgname); 445 } 446 XmlUtils.skipCurrentTag(parser); 447 continue; 448 449 } else if ("allow-in-power-save".equals(name) && allowAll) { 450 String pkgname = parser.getAttributeValue(null, "package"); 451 if (pkgname == null) { 452 Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at " 453 + parser.getPositionDescription()); 454 } else { 455 mAllowInPowerSave.add(pkgname); 456 } 457 XmlUtils.skipCurrentTag(parser); 458 continue; 459 460 } else if ("allow-in-data-usage-save".equals(name) && allowAll) { 461 String pkgname = parser.getAttributeValue(null, "package"); 462 if (pkgname == null) { 463 Slog.w(TAG, "<allow-in-data-usage-save> without package in " + permFile 464 + " at " + parser.getPositionDescription()); 465 } else { 466 mAllowInDataUsageSave.add(pkgname); 467 } 468 XmlUtils.skipCurrentTag(parser); 469 continue; 470 471 } else if ("allow-unthrottled-location".equals(name) && allowAll) { 472 String pkgname = parser.getAttributeValue(null, "package"); 473 if (pkgname == null) { 474 Slog.w(TAG, "<allow-unthrottled-location> without package in " 475 + permFile + " at " + parser.getPositionDescription()); 476 } else { 477 mAllowUnthrottledLocation.add(pkgname); 478 } 479 XmlUtils.skipCurrentTag(parser); 480 continue; 481 482 } else if ("allow-implicit-broadcast".equals(name) && allowAll) { 483 String action = parser.getAttributeValue(null, "action"); 484 if (action == null) { 485 Slog.w(TAG, "<allow-implicit-broadcast> without action in " + permFile 486 + " at " + parser.getPositionDescription()); 487 } else { 488 mAllowImplicitBroadcasts.add(action); 489 } 490 XmlUtils.skipCurrentTag(parser); 491 continue; 492 493 } else if ("app-link".equals(name) && allowAppConfigs) { 494 String pkgname = parser.getAttributeValue(null, "package"); 495 if (pkgname == null) { 496 Slog.w(TAG, "<app-link> without package in " + permFile + " at " 497 + parser.getPositionDescription()); 498 } else { 499 mLinkedApps.add(pkgname); 500 } 501 XmlUtils.skipCurrentTag(parser); 502 } else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) { 503 String pkgname = parser.getAttributeValue(null, "package"); 504 if (pkgname == null) { 505 Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile 506 + " at " + parser.getPositionDescription()); 507 } else { 508 mSystemUserWhitelistedApps.add(pkgname); 509 } 510 XmlUtils.skipCurrentTag(parser); 511 } else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) { 512 String pkgname = parser.getAttributeValue(null, "package"); 513 if (pkgname == null) { 514 Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile 515 + " at " + parser.getPositionDescription()); 516 } else { 517 mSystemUserBlacklistedApps.add(pkgname); 518 } 519 XmlUtils.skipCurrentTag(parser); 520 } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) { 521 String pkgname = parser.getAttributeValue(null, "package"); 522 String clsname = parser.getAttributeValue(null, "class"); 523 if (pkgname == null) { 524 Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile 525 + " at " + parser.getPositionDescription()); 526 } else if (clsname == null) { 527 Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile 528 + " at " + parser.getPositionDescription()); 529 } else { 530 mDefaultVrComponents.add(new ComponentName(pkgname, clsname)); 531 } 532 XmlUtils.skipCurrentTag(parser); 533 } else if ("backup-transport-whitelisted-service".equals(name) && allowFeatures) { 534 String serviceName = parser.getAttributeValue(null, "service"); 535 if (serviceName == null) { 536 Slog.w(TAG, "<backup-transport-whitelisted-service> without service in " 537 + permFile + " at " + parser.getPositionDescription()); 538 } else { 539 ComponentName cn = ComponentName.unflattenFromString(serviceName); 540 if (cn == null) { 541 Slog.w(TAG, 542 "<backup-transport-whitelisted-service> with invalid service name " 543 + serviceName + " in "+ permFile 544 + " at " + parser.getPositionDescription()); 545 } else { 546 mBackupTransportWhitelist.add(cn); 547 } 548 } 549 XmlUtils.skipCurrentTag(parser); 550 } else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name) 551 && allowAppConfigs) { 552 String pkgname = parser.getAttributeValue(null, "package"); 553 String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage"); 554 if (pkgname == null || carrierPkgname == null) { 555 Slog.w(TAG, "<disabled-until-used-preinstalled-carrier-associated-app" 556 + " without package or carrierAppPackage in " + permFile + " at " 557 + parser.getPositionDescription()); 558 } else { 559 List<String> associatedPkgs = 560 mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get( 561 carrierPkgname); 562 if (associatedPkgs == null) { 563 associatedPkgs = new ArrayList<>(); 564 mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put( 565 carrierPkgname, associatedPkgs); 566 } 567 associatedPkgs.add(pkgname); 568 } 569 XmlUtils.skipCurrentTag(parser); 570 } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) { 571 readPrivAppPermissions(parser); 572 } else { 573 XmlUtils.skipCurrentTag(parser); 574 continue; 575 } 576 } 577 } catch (XmlPullParserException e) { 578 Slog.w(TAG, "Got exception parsing permissions.", e); 579 } catch (IOException e) { 580 Slog.w(TAG, "Got exception parsing permissions.", e); 581 } finally { 582 IoUtils.closeQuietly(permReader); 583 } 584 585 // Some devices can be field-converted to FBE, so offer to splice in 586 // those features if not already defined by the static config 587 if (StorageManager.isFileEncryptedNativeOnly()) { 588 addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0); 589 addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0); 590 } 591 592 if (ActivityManager.isLowRamDeviceStatic()) { 593 addFeature(PackageManager.FEATURE_RAM_LOW, 0); 594 } else { 595 addFeature(PackageManager.FEATURE_RAM_NORMAL, 0); 596 } 597 598 for (String featureName : mUnavailableFeatures) { 599 removeFeature(featureName); 600 } 601 } 602 addFeature(String name, int version)603 private void addFeature(String name, int version) { 604 FeatureInfo fi = mAvailableFeatures.get(name); 605 if (fi == null) { 606 fi = new FeatureInfo(); 607 fi.name = name; 608 fi.version = version; 609 mAvailableFeatures.put(name, fi); 610 } else { 611 fi.version = Math.max(fi.version, version); 612 } 613 } 614 removeFeature(String name)615 private void removeFeature(String name) { 616 if (mAvailableFeatures.remove(name) != null) { 617 Slog.d(TAG, "Removed unavailable feature " + name); 618 } 619 } 620 readPermission(XmlPullParser parser, String name)621 void readPermission(XmlPullParser parser, String name) 622 throws IOException, XmlPullParserException { 623 if (mPermissions.containsKey(name)) { 624 throw new IllegalStateException("Duplicate permission definition for " + name); 625 } 626 627 final boolean perUser = XmlUtils.readBooleanAttribute(parser, "perUser", false); 628 final PermissionEntry perm = new PermissionEntry(name, perUser); 629 mPermissions.put(name, perm); 630 631 int outerDepth = parser.getDepth(); 632 int type; 633 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 634 && (type != XmlPullParser.END_TAG 635 || parser.getDepth() > outerDepth)) { 636 if (type == XmlPullParser.END_TAG 637 || type == XmlPullParser.TEXT) { 638 continue; 639 } 640 641 String tagName = parser.getName(); 642 if ("group".equals(tagName)) { 643 String gidStr = parser.getAttributeValue(null, "gid"); 644 if (gidStr != null) { 645 int gid = Process.getGidForName(gidStr); 646 perm.gids = appendInt(perm.gids, gid); 647 } else { 648 Slog.w(TAG, "<group> without gid at " 649 + parser.getPositionDescription()); 650 } 651 } 652 XmlUtils.skipCurrentTag(parser); 653 } 654 } 655 readPrivAppPermissions(XmlPullParser parser)656 void readPrivAppPermissions(XmlPullParser parser) throws IOException, XmlPullParserException { 657 String packageName = parser.getAttributeValue(null, "package"); 658 if (TextUtils.isEmpty(packageName)) { 659 Slog.w(TAG, "package is required for <privapp-permissions> in " 660 + parser.getPositionDescription()); 661 return; 662 } 663 664 ArraySet<String> permissions = mPrivAppPermissions.get(packageName); 665 if (permissions == null) { 666 permissions = new ArraySet<>(); 667 } 668 ArraySet<String> denyPermissions = mPrivAppDenyPermissions.get(packageName); 669 int depth = parser.getDepth(); 670 while (XmlUtils.nextElementWithin(parser, depth)) { 671 String name = parser.getName(); 672 if ("permission".equals(name)) { 673 String permName = parser.getAttributeValue(null, "name"); 674 if (TextUtils.isEmpty(permName)) { 675 Slog.w(TAG, "name is required for <permission> in " 676 + parser.getPositionDescription()); 677 continue; 678 } 679 permissions.add(permName); 680 } else if ("deny-permission".equals(name)) { 681 String permName = parser.getAttributeValue(null, "name"); 682 if (TextUtils.isEmpty(permName)) { 683 Slog.w(TAG, "name is required for <deny-permission> in " 684 + parser.getPositionDescription()); 685 continue; 686 } 687 if (denyPermissions == null) { 688 denyPermissions = new ArraySet<>(); 689 } 690 denyPermissions.add(permName); 691 } 692 } 693 mPrivAppPermissions.put(packageName, permissions); 694 if (denyPermissions != null) { 695 mPrivAppDenyPermissions.put(packageName, denyPermissions); 696 } 697 } 698 } 699