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.Build; 26 import android.os.Environment; 27 import android.os.Process; 28 import android.os.SystemProperties; 29 import android.os.storage.StorageManager; 30 import android.permission.PermissionManager.SplitPermissionInfo; 31 import android.text.TextUtils; 32 import android.util.ArrayMap; 33 import android.util.ArraySet; 34 import android.util.Slog; 35 import android.util.SparseArray; 36 import android.util.Xml; 37 38 import com.android.internal.util.XmlUtils; 39 40 import libcore.io.IoUtils; 41 42 import org.xmlpull.v1.XmlPullParser; 43 import org.xmlpull.v1.XmlPullParserException; 44 45 import java.io.File; 46 import java.io.FileNotFoundException; 47 import java.io.FileReader; 48 import java.io.IOException; 49 import java.util.ArrayList; 50 import java.util.Collections; 51 import java.util.List; 52 import java.util.Map; 53 54 /** 55 * Loads global system configuration info. 56 */ 57 public class SystemConfig { 58 static final String TAG = "SystemConfig"; 59 60 static SystemConfig sInstance; 61 62 // permission flag, determines which types of configuration are allowed to be read 63 private static final int ALLOW_FEATURES = 0x01; 64 private static final int ALLOW_LIBS = 0x02; 65 private static final int ALLOW_PERMISSIONS = 0x04; 66 private static final int ALLOW_APP_CONFIGS = 0x08; 67 private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10; 68 private static final int ALLOW_OEM_PERMISSIONS = 0x20; 69 private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x40; 70 private static final int ALLOW_ASSOCIATIONS = 0x80; 71 private static final int ALLOW_ALL = ~0; 72 73 // property for runtime configuration differentiation 74 private static final String SKU_PROPERTY = "ro.boot.product.hardware.sku"; 75 76 // Group-ids that are given to all packages as read from etc/permissions/*.xml. 77 int[] mGlobalGids; 78 79 // These are the built-in uid -> permission mappings that were read from the 80 // system configuration files. 81 final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>(); 82 83 final ArrayList<SplitPermissionInfo> mSplitPermissions = new ArrayList<>(); 84 85 public static final class SharedLibraryEntry { 86 public final String name; 87 public final String filename; 88 public final String[] dependencies; 89 SharedLibraryEntry(String name, String filename, String[] dependencies)90 SharedLibraryEntry(String name, String filename, String[] dependencies) { 91 this.name = name; 92 this.filename = filename; 93 this.dependencies = dependencies; 94 } 95 } 96 97 // These are the built-in shared libraries that were read from the 98 // system configuration files. Keys are the library names; values are 99 // the individual entries that contain information such as filename 100 // and dependencies. 101 final ArrayMap<String, SharedLibraryEntry> mSharedLibraries = new ArrayMap<>(); 102 103 // These are the features this devices supports that were read from the 104 // system configuration files. 105 final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>(); 106 107 // These are the features which this device doesn't support; the OEM 108 // partition uses these to opt-out of features from the system image. 109 final ArraySet<String> mUnavailableFeatures = new ArraySet<>(); 110 111 public static final class PermissionEntry { 112 public final String name; 113 public int[] gids; 114 public boolean perUser; 115 PermissionEntry(String name, boolean perUser)116 PermissionEntry(String name, boolean perUser) { 117 this.name = name; 118 this.perUser = perUser; 119 } 120 } 121 122 // These are the permission -> gid mappings that were read from the 123 // system configuration files. 124 final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>(); 125 126 // These are the packages that are white-listed to be able to run in the 127 // background while in power save mode (but not whitelisted from device idle modes), 128 // as read from the configuration files. 129 final ArraySet<String> mAllowInPowerSaveExceptIdle = new ArraySet<>(); 130 131 // These are the packages that are white-listed to be able to run in the 132 // background while in power save mode, as read from the configuration files. 133 final ArraySet<String> mAllowInPowerSave = new ArraySet<>(); 134 135 // These are the packages that are white-listed to be able to run in the 136 // background while in data-usage save mode, as read from the configuration files. 137 final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>(); 138 139 // These are the packages that are white-listed to be able to run background location 140 // without throttling, as read from the configuration files. 141 final ArraySet<String> mAllowUnthrottledLocation = new ArraySet<>(); 142 143 // These are the packages that are white-listed to be able to retrieve location even when user 144 // location settings are off, for emergency purposes, as read from the configuration files. 145 final ArraySet<String> mAllowIgnoreLocationSettings = new ArraySet<>(); 146 147 // These are the action strings of broadcasts which are whitelisted to 148 // be delivered anonymously even to apps which target O+. 149 final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>(); 150 151 // These are the package names of apps which should be in the 'always' 152 // URL-handling state upon factory reset. 153 final ArraySet<String> mLinkedApps = new ArraySet<>(); 154 155 // These are the packages that are whitelisted to be able to run as system user 156 final ArraySet<String> mSystemUserWhitelistedApps = new ArraySet<>(); 157 158 // These are the packages that should not run under system user 159 final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>(); 160 161 // These are the components that are enabled by default as VR mode listener services. 162 final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>(); 163 164 // These are the permitted backup transport service components 165 final ArraySet<ComponentName> mBackupTransportWhitelist = new ArraySet<>(); 166 167 // Package names that are exempted from private API blacklisting 168 final ArraySet<String> mHiddenApiPackageWhitelist = new ArraySet<>(); 169 170 // The list of carrier applications which should be disabled until used. 171 // This function suppresses update notifications for these pre-installed apps. 172 // In SubscriptionInfoUpdater, the listed applications are disabled until used when all of the 173 // following conditions are met. 174 // 1. Not currently carrier-privileged according to the inserted SIM 175 // 2. Pre-installed 176 // 3. In the default state (enabled but not explicitly) 177 // And SubscriptionInfoUpdater undoes this and marks the app enabled when a SIM is inserted 178 // that marks the app as carrier privileged. It also grants the app default permissions 179 // for Phone and Location. As such, apps MUST only ever be added to this list if they 180 // obtain user consent to access their location through other means. 181 final ArraySet<String> mDisabledUntilUsedPreinstalledCarrierApps = new ArraySet<>(); 182 183 // These are the packages of carrier-associated apps which should be disabled until used until 184 // a SIM is inserted which grants carrier privileges to that carrier app. 185 final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps = 186 new ArrayMap<>(); 187 188 final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>(); 189 final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>(); 190 191 final ArrayMap<String, ArraySet<String>> mVendorPrivAppPermissions = new ArrayMap<>(); 192 final ArrayMap<String, ArraySet<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>(); 193 194 final ArrayMap<String, ArraySet<String>> mProductPrivAppPermissions = new ArrayMap<>(); 195 final ArrayMap<String, ArraySet<String>> mProductPrivAppDenyPermissions = new ArrayMap<>(); 196 197 final ArrayMap<String, ArraySet<String>> mProductServicesPrivAppPermissions = new ArrayMap<>(); 198 final ArrayMap<String, ArraySet<String>> mProductServicesPrivAppDenyPermissions = 199 new ArrayMap<>(); 200 201 final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>(); 202 203 // Allowed associations between applications. If there are any entries 204 // for an app, those are the only associations allowed; otherwise, all associations 205 // are allowed. Allowing an association from app A to app B means app A can not 206 // associate with any other apps, but does not limit what apps B can associate with. 207 final ArrayMap<String, ArraySet<String>> mAllowedAssociations = new ArrayMap<>(); 208 209 private final ArraySet<String> mBugreportWhitelistedPackages = new ArraySet<>(); 210 getInstance()211 public static SystemConfig getInstance() { 212 synchronized (SystemConfig.class) { 213 if (sInstance == null) { 214 sInstance = new SystemConfig(); 215 } 216 return sInstance; 217 } 218 } 219 getGlobalGids()220 public int[] getGlobalGids() { 221 return mGlobalGids; 222 } 223 getSystemPermissions()224 public SparseArray<ArraySet<String>> getSystemPermissions() { 225 return mSystemPermissions; 226 } 227 getSplitPermissions()228 public ArrayList<SplitPermissionInfo> getSplitPermissions() { 229 return mSplitPermissions; 230 } 231 getSharedLibraries()232 public ArrayMap<String, SharedLibraryEntry> getSharedLibraries() { 233 return mSharedLibraries; 234 } 235 getAvailableFeatures()236 public ArrayMap<String, FeatureInfo> getAvailableFeatures() { 237 return mAvailableFeatures; 238 } 239 getPermissions()240 public ArrayMap<String, PermissionEntry> getPermissions() { 241 return mPermissions; 242 } 243 getAllowImplicitBroadcasts()244 public ArraySet<String> getAllowImplicitBroadcasts() { 245 return mAllowImplicitBroadcasts; 246 } 247 getAllowInPowerSaveExceptIdle()248 public ArraySet<String> getAllowInPowerSaveExceptIdle() { 249 return mAllowInPowerSaveExceptIdle; 250 } 251 getAllowInPowerSave()252 public ArraySet<String> getAllowInPowerSave() { 253 return mAllowInPowerSave; 254 } 255 getAllowInDataUsageSave()256 public ArraySet<String> getAllowInDataUsageSave() { 257 return mAllowInDataUsageSave; 258 } 259 getAllowUnthrottledLocation()260 public ArraySet<String> getAllowUnthrottledLocation() { 261 return mAllowUnthrottledLocation; 262 } 263 getAllowIgnoreLocationSettings()264 public ArraySet<String> getAllowIgnoreLocationSettings() { 265 return mAllowIgnoreLocationSettings; 266 } 267 getLinkedApps()268 public ArraySet<String> getLinkedApps() { 269 return mLinkedApps; 270 } 271 getSystemUserWhitelistedApps()272 public ArraySet<String> getSystemUserWhitelistedApps() { 273 return mSystemUserWhitelistedApps; 274 } 275 getSystemUserBlacklistedApps()276 public ArraySet<String> getSystemUserBlacklistedApps() { 277 return mSystemUserBlacklistedApps; 278 } 279 getHiddenApiWhitelistedApps()280 public ArraySet<String> getHiddenApiWhitelistedApps() { 281 return mHiddenApiPackageWhitelist; 282 } 283 getDefaultVrComponents()284 public ArraySet<ComponentName> getDefaultVrComponents() { 285 return mDefaultVrComponents; 286 } 287 getBackupTransportWhitelist()288 public ArraySet<ComponentName> getBackupTransportWhitelist() { 289 return mBackupTransportWhitelist; 290 } 291 getDisabledUntilUsedPreinstalledCarrierApps()292 public ArraySet<String> getDisabledUntilUsedPreinstalledCarrierApps() { 293 return mDisabledUntilUsedPreinstalledCarrierApps; 294 } 295 getDisabledUntilUsedPreinstalledCarrierAssociatedApps()296 public ArrayMap<String, List<String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps() { 297 return mDisabledUntilUsedPreinstalledCarrierAssociatedApps; 298 } 299 getPrivAppPermissions(String packageName)300 public ArraySet<String> getPrivAppPermissions(String packageName) { 301 return mPrivAppPermissions.get(packageName); 302 } 303 getPrivAppDenyPermissions(String packageName)304 public ArraySet<String> getPrivAppDenyPermissions(String packageName) { 305 return mPrivAppDenyPermissions.get(packageName); 306 } 307 getVendorPrivAppPermissions(String packageName)308 public ArraySet<String> getVendorPrivAppPermissions(String packageName) { 309 return mVendorPrivAppPermissions.get(packageName); 310 } 311 getVendorPrivAppDenyPermissions(String packageName)312 public ArraySet<String> getVendorPrivAppDenyPermissions(String packageName) { 313 return mVendorPrivAppDenyPermissions.get(packageName); 314 } 315 getProductPrivAppPermissions(String packageName)316 public ArraySet<String> getProductPrivAppPermissions(String packageName) { 317 return mProductPrivAppPermissions.get(packageName); 318 } 319 getProductPrivAppDenyPermissions(String packageName)320 public ArraySet<String> getProductPrivAppDenyPermissions(String packageName) { 321 return mProductPrivAppDenyPermissions.get(packageName); 322 } 323 getProductServicesPrivAppPermissions(String packageName)324 public ArraySet<String> getProductServicesPrivAppPermissions(String packageName) { 325 return mProductServicesPrivAppPermissions.get(packageName); 326 } 327 getProductServicesPrivAppDenyPermissions(String packageName)328 public ArraySet<String> getProductServicesPrivAppDenyPermissions(String packageName) { 329 return mProductServicesPrivAppDenyPermissions.get(packageName); 330 } 331 getOemPermissions(String packageName)332 public Map<String, Boolean> getOemPermissions(String packageName) { 333 final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName); 334 if (oemPermissions != null) { 335 return oemPermissions; 336 } 337 return Collections.emptyMap(); 338 } 339 getAllowedAssociations()340 public ArrayMap<String, ArraySet<String>> getAllowedAssociations() { 341 return mAllowedAssociations; 342 } 343 getBugreportWhitelistedPackages()344 public ArraySet<String> getBugreportWhitelistedPackages() { 345 return mBugreportWhitelistedPackages; 346 } 347 SystemConfig()348 SystemConfig() { 349 // Read configuration from system 350 readPermissions(Environment.buildPath( 351 Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL); 352 353 // Read configuration from the old permissions dir 354 readPermissions(Environment.buildPath( 355 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL); 356 357 // Vendors are only allowed to customize these 358 int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS 359 | ALLOW_ASSOCIATIONS; 360 if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) { 361 // For backward compatibility 362 vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS); 363 } 364 readPermissions(Environment.buildPath( 365 Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag); 366 readPermissions(Environment.buildPath( 367 Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag); 368 369 // Allow ODM to customize system configs as much as Vendor, because /odm is another 370 // vendor partition other than /vendor. 371 int odmPermissionFlag = vendorPermissionFlag; 372 readPermissions(Environment.buildPath( 373 Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag); 374 readPermissions(Environment.buildPath( 375 Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag); 376 377 String skuProperty = SystemProperties.get(SKU_PROPERTY, ""); 378 if (!skuProperty.isEmpty()) { 379 String skuDir = "sku_" + skuProperty; 380 381 readPermissions(Environment.buildPath( 382 Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag); 383 readPermissions(Environment.buildPath( 384 Environment.getOdmDirectory(), "etc", "permissions", skuDir), 385 odmPermissionFlag); 386 } 387 388 // Allow OEM to customize these 389 int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS; 390 readPermissions(Environment.buildPath( 391 Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag); 392 readPermissions(Environment.buildPath( 393 Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag); 394 395 // Allow Product to customize all system configs 396 readPermissions(Environment.buildPath( 397 Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL); 398 readPermissions(Environment.buildPath( 399 Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL); 400 401 // Allow /product_services to customize all system configs 402 readPermissions(Environment.buildPath( 403 Environment.getProductServicesDirectory(), "etc", "sysconfig"), ALLOW_ALL); 404 readPermissions(Environment.buildPath( 405 Environment.getProductServicesDirectory(), "etc", "permissions"), ALLOW_ALL); 406 } 407 readPermissions(File libraryDir, int permissionFlag)408 void readPermissions(File libraryDir, int permissionFlag) { 409 // Read permissions from given directory. 410 if (!libraryDir.exists() || !libraryDir.isDirectory()) { 411 if (permissionFlag == ALLOW_ALL) { 412 Slog.w(TAG, "No directory " + libraryDir + ", skipping"); 413 } 414 return; 415 } 416 if (!libraryDir.canRead()) { 417 Slog.w(TAG, "Directory " + libraryDir + " cannot be read"); 418 return; 419 } 420 421 // Iterate over the files in the directory and scan .xml files 422 File platformFile = null; 423 for (File f : libraryDir.listFiles()) { 424 if (!f.isFile()) { 425 continue; 426 } 427 428 // We'll read platform.xml last 429 if (f.getPath().endsWith("etc/permissions/platform.xml")) { 430 platformFile = f; 431 continue; 432 } 433 434 if (!f.getPath().endsWith(".xml")) { 435 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring"); 436 continue; 437 } 438 if (!f.canRead()) { 439 Slog.w(TAG, "Permissions library file " + f + " cannot be read"); 440 continue; 441 } 442 443 readPermissionsFromXml(f, permissionFlag); 444 } 445 446 // Read platform permissions last so it will take precedence 447 if (platformFile != null) { 448 readPermissionsFromXml(platformFile, permissionFlag); 449 } 450 } 451 logNotAllowedInPartition(String name, File permFile, XmlPullParser parser)452 private void logNotAllowedInPartition(String name, File permFile, XmlPullParser parser) { 453 Slog.w(TAG, "<" + name + "> not allowed in partition of " 454 + permFile + " at " + parser.getPositionDescription()); 455 } 456 readPermissionsFromXml(File permFile, int permissionFlag)457 private void readPermissionsFromXml(File permFile, int permissionFlag) { 458 FileReader permReader = null; 459 try { 460 permReader = new FileReader(permFile); 461 } catch (FileNotFoundException e) { 462 Slog.w(TAG, "Couldn't find or open permissions file " + permFile); 463 return; 464 } 465 466 final boolean lowRam = ActivityManager.isLowRamDeviceStatic(); 467 468 try { 469 XmlPullParser parser = Xml.newPullParser(); 470 parser.setInput(permReader); 471 472 int type; 473 while ((type=parser.next()) != parser.START_TAG 474 && type != parser.END_DOCUMENT) { 475 ; 476 } 477 478 if (type != parser.START_TAG) { 479 throw new XmlPullParserException("No start tag found"); 480 } 481 482 if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) { 483 throw new XmlPullParserException("Unexpected start tag in " + permFile 484 + ": found " + parser.getName() + ", expected 'permissions' or 'config'"); 485 } 486 487 final boolean allowAll = permissionFlag == ALLOW_ALL; 488 final boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0; 489 final boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0; 490 final boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0; 491 final boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0; 492 final boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) 493 != 0; 494 final boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0; 495 final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) 496 != 0; 497 final boolean allowAssociations = (permissionFlag & ALLOW_ASSOCIATIONS) != 0; 498 while (true) { 499 XmlUtils.nextElement(parser); 500 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { 501 break; 502 } 503 504 String name = parser.getName(); 505 if (name == null) { 506 XmlUtils.skipCurrentTag(parser); 507 continue; 508 } 509 switch (name) { 510 case "group": { 511 if (allowAll) { 512 String gidStr = parser.getAttributeValue(null, "gid"); 513 if (gidStr != null) { 514 int gid = android.os.Process.getGidForName(gidStr); 515 mGlobalGids = appendInt(mGlobalGids, gid); 516 } else { 517 Slog.w(TAG, "<" + name + "> without gid in " + permFile + " at " 518 + parser.getPositionDescription()); 519 } 520 } else { 521 logNotAllowedInPartition(name, permFile, parser); 522 } 523 XmlUtils.skipCurrentTag(parser); 524 } break; 525 case "permission": { 526 if (allowPermissions) { 527 String perm = parser.getAttributeValue(null, "name"); 528 if (perm == null) { 529 Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " 530 + parser.getPositionDescription()); 531 XmlUtils.skipCurrentTag(parser); 532 break; 533 } 534 perm = perm.intern(); 535 readPermission(parser, perm); 536 } else { 537 logNotAllowedInPartition(name, permFile, parser); 538 XmlUtils.skipCurrentTag(parser); 539 } 540 } break; 541 case "assign-permission": { 542 if (allowPermissions) { 543 String perm = parser.getAttributeValue(null, "name"); 544 if (perm == null) { 545 Slog.w(TAG, "<" + name + "> without name in " + permFile 546 + " at " + parser.getPositionDescription()); 547 XmlUtils.skipCurrentTag(parser); 548 break; 549 } 550 String uidStr = parser.getAttributeValue(null, "uid"); 551 if (uidStr == null) { 552 Slog.w(TAG, "<" + name + "> without uid in " + permFile 553 + " at " + parser.getPositionDescription()); 554 XmlUtils.skipCurrentTag(parser); 555 break; 556 } 557 int uid = Process.getUidForName(uidStr); 558 if (uid < 0) { 559 Slog.w(TAG, "<" + name + "> with unknown uid \"" 560 + uidStr + " in " + permFile + " at " 561 + parser.getPositionDescription()); 562 XmlUtils.skipCurrentTag(parser); 563 break; 564 } 565 perm = perm.intern(); 566 ArraySet<String> perms = mSystemPermissions.get(uid); 567 if (perms == null) { 568 perms = new ArraySet<String>(); 569 mSystemPermissions.put(uid, perms); 570 } 571 perms.add(perm); 572 } else { 573 logNotAllowedInPartition(name, permFile, parser); 574 } 575 XmlUtils.skipCurrentTag(parser); 576 } break; 577 case "split-permission": { 578 if (allowPermissions) { 579 readSplitPermission(parser, permFile); 580 } else { 581 logNotAllowedInPartition(name, permFile, parser); 582 XmlUtils.skipCurrentTag(parser); 583 } 584 } break; 585 case "library": { 586 if (allowLibs) { 587 String lname = parser.getAttributeValue(null, "name"); 588 String lfile = parser.getAttributeValue(null, "file"); 589 String ldependency = parser.getAttributeValue(null, "dependency"); 590 if (lname == null) { 591 Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " 592 + parser.getPositionDescription()); 593 } else if (lfile == null) { 594 Slog.w(TAG, "<" + name + "> without file in " + permFile + " at " 595 + parser.getPositionDescription()); 596 } else { 597 //Log.i(TAG, "Got library " + lname + " in " + lfile); 598 SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, 599 ldependency == null ? new String[0] : ldependency.split(":")); 600 mSharedLibraries.put(lname, entry); 601 } 602 } else { 603 logNotAllowedInPartition(name, permFile, parser); 604 } 605 XmlUtils.skipCurrentTag(parser); 606 } break; 607 case "feature": { 608 if (allowFeatures) { 609 String fname = parser.getAttributeValue(null, "name"); 610 int fversion = XmlUtils.readIntAttribute(parser, "version", 0); 611 boolean allowed; 612 if (!lowRam) { 613 allowed = true; 614 } else { 615 String notLowRam = parser.getAttributeValue(null, "notLowRam"); 616 allowed = !"true".equals(notLowRam); 617 } 618 if (fname == null) { 619 Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " 620 + parser.getPositionDescription()); 621 } else if (allowed) { 622 addFeature(fname, fversion); 623 } 624 } else { 625 logNotAllowedInPartition(name, permFile, parser); 626 } 627 XmlUtils.skipCurrentTag(parser); 628 } break; 629 case "unavailable-feature": { 630 if (allowFeatures) { 631 String fname = parser.getAttributeValue(null, "name"); 632 if (fname == null) { 633 Slog.w(TAG, "<" + name + "> without name in " + permFile 634 + " at " + parser.getPositionDescription()); 635 } else { 636 mUnavailableFeatures.add(fname); 637 } 638 } else { 639 logNotAllowedInPartition(name, permFile, parser); 640 } 641 XmlUtils.skipCurrentTag(parser); 642 } break; 643 case "allow-in-power-save-except-idle": { 644 if (allowAll) { 645 String pkgname = parser.getAttributeValue(null, "package"); 646 if (pkgname == null) { 647 Slog.w(TAG, "<" + name + "> without package in " 648 + permFile + " at " + parser.getPositionDescription()); 649 } else { 650 mAllowInPowerSaveExceptIdle.add(pkgname); 651 } 652 } else { 653 logNotAllowedInPartition(name, permFile, parser); 654 } 655 XmlUtils.skipCurrentTag(parser); 656 } break; 657 case "allow-in-power-save": { 658 if (allowAll) { 659 String pkgname = parser.getAttributeValue(null, "package"); 660 if (pkgname == null) { 661 Slog.w(TAG, "<" + name + "> without package in " 662 + permFile + " at " + parser.getPositionDescription()); 663 } else { 664 mAllowInPowerSave.add(pkgname); 665 } 666 } else { 667 logNotAllowedInPartition(name, permFile, parser); 668 } 669 XmlUtils.skipCurrentTag(parser); 670 } break; 671 case "allow-in-data-usage-save": { 672 if (allowAll) { 673 String pkgname = parser.getAttributeValue(null, "package"); 674 if (pkgname == null) { 675 Slog.w(TAG, "<" + name + "> without package in " 676 + permFile + " at " + parser.getPositionDescription()); 677 } else { 678 mAllowInDataUsageSave.add(pkgname); 679 } 680 } else { 681 logNotAllowedInPartition(name, permFile, parser); 682 } 683 XmlUtils.skipCurrentTag(parser); 684 } break; 685 case "allow-unthrottled-location": { 686 if (allowAll) { 687 String pkgname = parser.getAttributeValue(null, "package"); 688 if (pkgname == null) { 689 Slog.w(TAG, "<" + name + "> without package in " 690 + permFile + " at " + parser.getPositionDescription()); 691 } else { 692 mAllowUnthrottledLocation.add(pkgname); 693 } 694 } else { 695 logNotAllowedInPartition(name, permFile, parser); 696 } 697 XmlUtils.skipCurrentTag(parser); 698 } break; 699 case "allow-ignore-location-settings": { 700 if (allowAll) { 701 String pkgname = parser.getAttributeValue(null, "package"); 702 if (pkgname == null) { 703 Slog.w(TAG, "<" + name + "> without package in " 704 + permFile + " at " + parser.getPositionDescription()); 705 } else { 706 mAllowIgnoreLocationSettings.add(pkgname); 707 } 708 } else { 709 logNotAllowedInPartition(name, permFile, parser); 710 } 711 XmlUtils.skipCurrentTag(parser); 712 } break; 713 case "allow-implicit-broadcast": { 714 if (allowAll) { 715 String action = parser.getAttributeValue(null, "action"); 716 if (action == null) { 717 Slog.w(TAG, "<" + name + "> without action in " 718 + permFile + " at " + parser.getPositionDescription()); 719 } else { 720 mAllowImplicitBroadcasts.add(action); 721 } 722 } else { 723 logNotAllowedInPartition(name, permFile, parser); 724 } 725 XmlUtils.skipCurrentTag(parser); 726 } break; 727 case "app-link": { 728 if (allowAppConfigs) { 729 String pkgname = parser.getAttributeValue(null, "package"); 730 if (pkgname == null) { 731 Slog.w(TAG, "<" + name + "> without package in " + permFile 732 + " at " + parser.getPositionDescription()); 733 } else { 734 mLinkedApps.add(pkgname); 735 } 736 } else { 737 logNotAllowedInPartition(name, permFile, parser); 738 } 739 XmlUtils.skipCurrentTag(parser); 740 } break; 741 case "system-user-whitelisted-app": { 742 if (allowAppConfigs) { 743 String pkgname = parser.getAttributeValue(null, "package"); 744 if (pkgname == null) { 745 Slog.w(TAG, "<" + name + "> without package in " 746 + permFile + " at " + parser.getPositionDescription()); 747 } else { 748 mSystemUserWhitelistedApps.add(pkgname); 749 } 750 } else { 751 logNotAllowedInPartition(name, permFile, parser); 752 } 753 XmlUtils.skipCurrentTag(parser); 754 } break; 755 case "system-user-blacklisted-app": { 756 if (allowAppConfigs) { 757 String pkgname = parser.getAttributeValue(null, "package"); 758 if (pkgname == null) { 759 Slog.w(TAG, "<" + name + "> without package in " 760 + permFile + " at " + parser.getPositionDescription()); 761 } else { 762 mSystemUserBlacklistedApps.add(pkgname); 763 } 764 } else { 765 logNotAllowedInPartition(name, permFile, parser); 766 } 767 XmlUtils.skipCurrentTag(parser); 768 } break; 769 case "default-enabled-vr-app": { 770 if (allowAppConfigs) { 771 String pkgname = parser.getAttributeValue(null, "package"); 772 String clsname = parser.getAttributeValue(null, "class"); 773 if (pkgname == null) { 774 Slog.w(TAG, "<" + name + "> without package in " 775 + permFile + " at " + parser.getPositionDescription()); 776 } else if (clsname == null) { 777 Slog.w(TAG, "<" + name + "> without class in " 778 + permFile + " at " + parser.getPositionDescription()); 779 } else { 780 mDefaultVrComponents.add(new ComponentName(pkgname, clsname)); 781 } 782 } else { 783 logNotAllowedInPartition(name, permFile, parser); 784 } 785 XmlUtils.skipCurrentTag(parser); 786 } break; 787 case "backup-transport-whitelisted-service": { 788 if (allowFeatures) { 789 String serviceName = parser.getAttributeValue(null, "service"); 790 if (serviceName == null) { 791 Slog.w(TAG, "<" + name + "> without service in " 792 + permFile + " at " + parser.getPositionDescription()); 793 } else { 794 ComponentName cn = ComponentName.unflattenFromString(serviceName); 795 if (cn == null) { 796 Slog.w(TAG, "<" + name + "> with invalid service name " 797 + serviceName + " in " + permFile 798 + " at " + parser.getPositionDescription()); 799 } else { 800 mBackupTransportWhitelist.add(cn); 801 } 802 } 803 } else { 804 logNotAllowedInPartition(name, permFile, parser); 805 } 806 XmlUtils.skipCurrentTag(parser); 807 } break; 808 case "disabled-until-used-preinstalled-carrier-associated-app": { 809 if (allowAppConfigs) { 810 String pkgname = parser.getAttributeValue(null, "package"); 811 String carrierPkgname = parser.getAttributeValue(null, 812 "carrierAppPackage"); 813 if (pkgname == null || carrierPkgname == null) { 814 Slog.w(TAG, "<" + name 815 + "> without package or carrierAppPackage in " + permFile 816 + " at " + parser.getPositionDescription()); 817 } else { 818 List<String> associatedPkgs = 819 mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get( 820 carrierPkgname); 821 if (associatedPkgs == null) { 822 associatedPkgs = new ArrayList<>(); 823 mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put( 824 carrierPkgname, associatedPkgs); 825 } 826 associatedPkgs.add(pkgname); 827 } 828 } else { 829 logNotAllowedInPartition(name, permFile, parser); 830 } 831 XmlUtils.skipCurrentTag(parser); 832 } break; 833 case "disabled-until-used-preinstalled-carrier-app": { 834 if (allowAppConfigs) { 835 String pkgname = parser.getAttributeValue(null, "package"); 836 if (pkgname == null) { 837 Slog.w(TAG, 838 "<" + name + "> without " 839 + "package in " + permFile + " at " 840 + parser.getPositionDescription()); 841 } else { 842 mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname); 843 } 844 } else { 845 logNotAllowedInPartition(name, permFile, parser); 846 } 847 XmlUtils.skipCurrentTag(parser); 848 } break; 849 case "privapp-permissions": { 850 if (allowPrivappPermissions) { 851 // privapp permissions from system, vendor, product and product_services 852 // partitions are stored separately. This is to prevent xml files in 853 // the vendor partition from granting permissions to priv apps in the 854 // system partition and vice versa. 855 boolean vendor = permFile.toPath().startsWith( 856 Environment.getVendorDirectory().toPath() + "/") 857 || permFile.toPath().startsWith( 858 Environment.getOdmDirectory().toPath() + "/"); 859 boolean product = permFile.toPath().startsWith( 860 Environment.getProductDirectory().toPath() + "/"); 861 boolean productServices = permFile.toPath().startsWith( 862 Environment.getProductServicesDirectory().toPath() + "/"); 863 if (vendor) { 864 readPrivAppPermissions(parser, mVendorPrivAppPermissions, 865 mVendorPrivAppDenyPermissions); 866 } else if (product) { 867 readPrivAppPermissions(parser, mProductPrivAppPermissions, 868 mProductPrivAppDenyPermissions); 869 } else if (productServices) { 870 readPrivAppPermissions(parser, mProductServicesPrivAppPermissions, 871 mProductServicesPrivAppDenyPermissions); 872 } else { 873 readPrivAppPermissions(parser, mPrivAppPermissions, 874 mPrivAppDenyPermissions); 875 } 876 } else { 877 logNotAllowedInPartition(name, permFile, parser); 878 XmlUtils.skipCurrentTag(parser); 879 } 880 } break; 881 case "oem-permissions": { 882 if (allowOemPermissions) { 883 readOemPermissions(parser); 884 } else { 885 logNotAllowedInPartition(name, permFile, parser); 886 XmlUtils.skipCurrentTag(parser); 887 } 888 } break; 889 case "hidden-api-whitelisted-app": { 890 if (allowApiWhitelisting) { 891 String pkgname = parser.getAttributeValue(null, "package"); 892 if (pkgname == null) { 893 Slog.w(TAG, "<" + name + "> without package in " 894 + permFile + " at " + parser.getPositionDescription()); 895 } else { 896 mHiddenApiPackageWhitelist.add(pkgname); 897 } 898 } else { 899 logNotAllowedInPartition(name, permFile, parser); 900 } 901 XmlUtils.skipCurrentTag(parser); 902 } break; 903 case "allow-association": { 904 if (allowAssociations) { 905 String target = parser.getAttributeValue(null, "target"); 906 if (target == null) { 907 Slog.w(TAG, "<" + name + "> without target in " + permFile 908 + " at " + parser.getPositionDescription()); 909 XmlUtils.skipCurrentTag(parser); 910 break; 911 } 912 String allowed = parser.getAttributeValue(null, "allowed"); 913 if (allowed == null) { 914 Slog.w(TAG, "<" + name + "> without allowed in " + permFile 915 + " at " + parser.getPositionDescription()); 916 XmlUtils.skipCurrentTag(parser); 917 break; 918 } 919 target = target.intern(); 920 allowed = allowed.intern(); 921 ArraySet<String> associations = mAllowedAssociations.get(target); 922 if (associations == null) { 923 associations = new ArraySet<>(); 924 mAllowedAssociations.put(target, associations); 925 } 926 Slog.i(TAG, "Adding association: " + target + " <- " + allowed); 927 associations.add(allowed); 928 } else { 929 logNotAllowedInPartition(name, permFile, parser); 930 } 931 XmlUtils.skipCurrentTag(parser); 932 } break; 933 case "bugreport-whitelisted": { 934 String pkgname = parser.getAttributeValue(null, "package"); 935 if (pkgname == null) { 936 Slog.w(TAG, "<" + name + "> without package in " + permFile 937 + " at " + parser.getPositionDescription()); 938 } else { 939 mBugreportWhitelistedPackages.add(pkgname); 940 } 941 XmlUtils.skipCurrentTag(parser); 942 } break; 943 default: { 944 Slog.w(TAG, "Tag " + name + " is unknown in " 945 + permFile + " at " + parser.getPositionDescription()); 946 XmlUtils.skipCurrentTag(parser); 947 } break; 948 } 949 } 950 } catch (XmlPullParserException e) { 951 Slog.w(TAG, "Got exception parsing permissions.", e); 952 } catch (IOException e) { 953 Slog.w(TAG, "Got exception parsing permissions.", e); 954 } finally { 955 IoUtils.closeQuietly(permReader); 956 } 957 958 // Some devices can be field-converted to FBE, so offer to splice in 959 // those features if not already defined by the static config 960 if (StorageManager.isFileEncryptedNativeOnly()) { 961 addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0); 962 addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0); 963 } 964 965 // Help legacy devices that may not have updated their static config 966 if (StorageManager.hasAdoptable()) { 967 addFeature(PackageManager.FEATURE_ADOPTABLE_STORAGE, 0); 968 } 969 970 if (ActivityManager.isLowRamDeviceStatic()) { 971 addFeature(PackageManager.FEATURE_RAM_LOW, 0); 972 } else { 973 addFeature(PackageManager.FEATURE_RAM_NORMAL, 0); 974 } 975 976 for (String featureName : mUnavailableFeatures) { 977 removeFeature(featureName); 978 } 979 } 980 addFeature(String name, int version)981 private void addFeature(String name, int version) { 982 FeatureInfo fi = mAvailableFeatures.get(name); 983 if (fi == null) { 984 fi = new FeatureInfo(); 985 fi.name = name; 986 fi.version = version; 987 mAvailableFeatures.put(name, fi); 988 } else { 989 fi.version = Math.max(fi.version, version); 990 } 991 } 992 removeFeature(String name)993 private void removeFeature(String name) { 994 if (mAvailableFeatures.remove(name) != null) { 995 Slog.d(TAG, "Removed unavailable feature " + name); 996 } 997 } 998 readPermission(XmlPullParser parser, String name)999 void readPermission(XmlPullParser parser, String name) 1000 throws IOException, XmlPullParserException { 1001 if (mPermissions.containsKey(name)) { 1002 throw new IllegalStateException("Duplicate permission definition for " + name); 1003 } 1004 1005 final boolean perUser = XmlUtils.readBooleanAttribute(parser, "perUser", false); 1006 final PermissionEntry perm = new PermissionEntry(name, perUser); 1007 mPermissions.put(name, perm); 1008 1009 int outerDepth = parser.getDepth(); 1010 int type; 1011 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 1012 && (type != XmlPullParser.END_TAG 1013 || parser.getDepth() > outerDepth)) { 1014 if (type == XmlPullParser.END_TAG 1015 || type == XmlPullParser.TEXT) { 1016 continue; 1017 } 1018 1019 String tagName = parser.getName(); 1020 if ("group".equals(tagName)) { 1021 String gidStr = parser.getAttributeValue(null, "gid"); 1022 if (gidStr != null) { 1023 int gid = Process.getGidForName(gidStr); 1024 perm.gids = appendInt(perm.gids, gid); 1025 } else { 1026 Slog.w(TAG, "<group> without gid at " 1027 + parser.getPositionDescription()); 1028 } 1029 } 1030 XmlUtils.skipCurrentTag(parser); 1031 } 1032 } 1033 readPrivAppPermissions(XmlPullParser parser, ArrayMap<String, ArraySet<String>> grantMap, ArrayMap<String, ArraySet<String>> denyMap)1034 private void readPrivAppPermissions(XmlPullParser parser, 1035 ArrayMap<String, ArraySet<String>> grantMap, 1036 ArrayMap<String, ArraySet<String>> denyMap) 1037 throws IOException, XmlPullParserException { 1038 String packageName = parser.getAttributeValue(null, "package"); 1039 if (TextUtils.isEmpty(packageName)) { 1040 Slog.w(TAG, "package is required for <privapp-permissions> in " 1041 + parser.getPositionDescription()); 1042 return; 1043 } 1044 1045 ArraySet<String> permissions = grantMap.get(packageName); 1046 if (permissions == null) { 1047 permissions = new ArraySet<>(); 1048 } 1049 ArraySet<String> denyPermissions = denyMap.get(packageName); 1050 int depth = parser.getDepth(); 1051 while (XmlUtils.nextElementWithin(parser, depth)) { 1052 String name = parser.getName(); 1053 if ("permission".equals(name)) { 1054 String permName = parser.getAttributeValue(null, "name"); 1055 if (TextUtils.isEmpty(permName)) { 1056 Slog.w(TAG, "name is required for <permission> in " 1057 + parser.getPositionDescription()); 1058 continue; 1059 } 1060 permissions.add(permName); 1061 } else if ("deny-permission".equals(name)) { 1062 String permName = parser.getAttributeValue(null, "name"); 1063 if (TextUtils.isEmpty(permName)) { 1064 Slog.w(TAG, "name is required for <deny-permission> in " 1065 + parser.getPositionDescription()); 1066 continue; 1067 } 1068 if (denyPermissions == null) { 1069 denyPermissions = new ArraySet<>(); 1070 } 1071 denyPermissions.add(permName); 1072 } 1073 } 1074 grantMap.put(packageName, permissions); 1075 if (denyPermissions != null) { 1076 denyMap.put(packageName, denyPermissions); 1077 } 1078 } 1079 readOemPermissions(XmlPullParser parser)1080 void readOemPermissions(XmlPullParser parser) throws IOException, XmlPullParserException { 1081 final String packageName = parser.getAttributeValue(null, "package"); 1082 if (TextUtils.isEmpty(packageName)) { 1083 Slog.w(TAG, "package is required for <oem-permissions> in " 1084 + parser.getPositionDescription()); 1085 return; 1086 } 1087 1088 ArrayMap<String, Boolean> permissions = mOemPermissions.get(packageName); 1089 if (permissions == null) { 1090 permissions = new ArrayMap<>(); 1091 } 1092 final int depth = parser.getDepth(); 1093 while (XmlUtils.nextElementWithin(parser, depth)) { 1094 final String name = parser.getName(); 1095 if ("permission".equals(name)) { 1096 final String permName = parser.getAttributeValue(null, "name"); 1097 if (TextUtils.isEmpty(permName)) { 1098 Slog.w(TAG, "name is required for <permission> in " 1099 + parser.getPositionDescription()); 1100 continue; 1101 } 1102 permissions.put(permName, Boolean.TRUE); 1103 } else if ("deny-permission".equals(name)) { 1104 String permName = parser.getAttributeValue(null, "name"); 1105 if (TextUtils.isEmpty(permName)) { 1106 Slog.w(TAG, "name is required for <deny-permission> in " 1107 + parser.getPositionDescription()); 1108 continue; 1109 } 1110 permissions.put(permName, Boolean.FALSE); 1111 } 1112 } 1113 mOemPermissions.put(packageName, permissions); 1114 } 1115 readSplitPermission(XmlPullParser parser, File permFile)1116 private void readSplitPermission(XmlPullParser parser, File permFile) 1117 throws IOException, XmlPullParserException { 1118 String splitPerm = parser.getAttributeValue(null, "name"); 1119 if (splitPerm == null) { 1120 Slog.w(TAG, "<split-permission> without name in " + permFile + " at " 1121 + parser.getPositionDescription()); 1122 XmlUtils.skipCurrentTag(parser); 1123 return; 1124 } 1125 String targetSdkStr = parser.getAttributeValue(null, "targetSdk"); 1126 int targetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT + 1; 1127 if (!TextUtils.isEmpty(targetSdkStr)) { 1128 try { 1129 targetSdk = Integer.parseInt(targetSdkStr); 1130 } catch (NumberFormatException e) { 1131 Slog.w(TAG, "<split-permission> targetSdk not an integer in " + permFile + " at " 1132 + parser.getPositionDescription()); 1133 XmlUtils.skipCurrentTag(parser); 1134 return; 1135 } 1136 } 1137 final int depth = parser.getDepth(); 1138 List<String> newPermissions = new ArrayList<>(); 1139 while (XmlUtils.nextElementWithin(parser, depth)) { 1140 String name = parser.getName(); 1141 if ("new-permission".equals(name)) { 1142 final String newName = parser.getAttributeValue(null, "name"); 1143 if (TextUtils.isEmpty(newName)) { 1144 Slog.w(TAG, "name is required for <new-permission> in " 1145 + parser.getPositionDescription()); 1146 continue; 1147 } 1148 newPermissions.add(newName); 1149 } else { 1150 XmlUtils.skipCurrentTag(parser); 1151 } 1152 } 1153 if (!newPermissions.isEmpty()) { 1154 mSplitPermissions.add(new SplitPermissionInfo(splitPerm, newPermissions, targetSdk)); 1155 } 1156 } 1157 } 1158