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