1 /* 2 * Copyright (C) 2022 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.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.app.ActivityManager; 24 import android.content.ComponentName; 25 import android.content.pm.FeatureInfo; 26 import android.content.pm.PackageManager; 27 import android.os.Build; 28 import android.os.CarrierAssociatedAppEntry; 29 import android.os.Environment; 30 import android.os.FileUtils; 31 import android.os.Process; 32 import android.os.SystemProperties; 33 import android.os.Trace; 34 import android.os.VintfRuntimeInfo; 35 import android.os.incremental.IncrementalManager; 36 import android.os.storage.StorageManager; 37 import android.permission.PermissionManager.SplitPermissionInfo; 38 import android.sysprop.ApexProperties; 39 import android.text.TextUtils; 40 import android.util.ArrayMap; 41 import android.util.ArraySet; 42 import android.util.Slog; 43 import android.util.SparseArray; 44 import android.util.TimingsTraceLog; 45 import android.util.Xml; 46 47 import com.android.internal.annotations.VisibleForTesting; 48 import com.android.internal.util.XmlUtils; 49 import com.android.modules.utils.build.UnboundedSdkLevel; 50 import com.android.server.pm.permission.PermissionAllowlist; 51 52 import libcore.io.IoUtils; 53 import libcore.util.EmptyArray; 54 55 import org.xmlpull.v1.XmlPullParser; 56 import org.xmlpull.v1.XmlPullParserException; 57 58 import java.io.BufferedReader; 59 import java.io.File; 60 import java.io.FileNotFoundException; 61 import java.io.FileReader; 62 import java.io.IOException; 63 import java.nio.file.Files; 64 import java.nio.file.Path; 65 import java.nio.file.Paths; 66 import java.util.ArrayList; 67 import java.util.Collections; 68 import java.util.List; 69 import java.util.Map; 70 import java.util.Set; 71 72 /** 73 * Loads global system configuration info. 74 * Note: Initializing this class hits the disk and is slow. This class should generally only be 75 * accessed by the system_server process. 76 * 77 * @hide 78 */ 79 public class SystemConfig { 80 static final String TAG = "SystemConfig"; 81 82 static SystemConfig sInstance; 83 84 // permission flag, determines which types of configuration are allowed to be read 85 private static final int ALLOW_FEATURES = 0x001; 86 private static final int ALLOW_LIBS = 0x002; 87 private static final int ALLOW_PERMISSIONS = 0x004; 88 private static final int ALLOW_APP_CONFIGS = 0x008; 89 private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x010; 90 private static final int ALLOW_OEM_PERMISSIONS = 0x020; 91 private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x040; 92 private static final int ALLOW_ASSOCIATIONS = 0x080; 93 // ALLOW_OVERRIDE_APP_RESTRICTIONS allows to use "allow-in-power-save-except-idle", 94 // "allow-in-power-save", "allow-in-data-usage-save","allow-unthrottled-location", 95 // "allow-ignore-location-settings" and "allow-adas-location-settings". 96 private static final int ALLOW_OVERRIDE_APP_RESTRICTIONS = 0x100; 97 private static final int ALLOW_IMPLICIT_BROADCASTS = 0x200; 98 private static final int ALLOW_VENDOR_APEX = 0x400; 99 private static final int ALLOW_ALL = ~0; 100 101 // property for runtime configuration differentiation 102 private static final String SKU_PROPERTY = "ro.boot.product.hardware.sku"; 103 104 // property for runtime configuration differentiation in vendor 105 private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku"; 106 107 private static final ArrayMap<String, ArraySet<String>> EMPTY_PERMISSIONS = 108 new ArrayMap<>(); 109 110 // Group-ids that are given to all packages as read from etc/permissions/*.xml. 111 int[] mGlobalGids = EmptyArray.INT; 112 113 // These are the built-in uid -> permission mappings that were read from the 114 // system configuration files. 115 final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>(); 116 117 final ArrayList<SplitPermissionInfo> mSplitPermissions = new ArrayList<>(); 118 isAtLeastSdkLevel(String version)119 private static boolean isAtLeastSdkLevel(String version) { 120 try { 121 return UnboundedSdkLevel.isAtLeast(version); 122 } catch (IllegalArgumentException e) { 123 // UnboundedSdkLevel throws when it sees a known old codename 124 return false; 125 } 126 } 127 isAtMostSdkLevel(String version)128 private static boolean isAtMostSdkLevel(String version) { 129 try { 130 return UnboundedSdkLevel.isAtMost(version); 131 } catch (IllegalArgumentException e) { 132 // UnboundedSdkLevel throws when it sees a known old codename 133 return true; 134 } 135 } 136 137 public static final class SharedLibraryEntry { 138 public final String name; 139 public final String filename; 140 public final String[] dependencies; 141 142 /** 143 * SDK version this library was added to the BOOTCLASSPATH. 144 * 145 * <p>At the SDK level specified in this field and higher, the apps' uses-library tags for 146 * this library will be ignored, since the library is always available on BOOTCLASSPATH. 147 * 148 * <p>0 means not specified. 149 */ 150 public final String onBootclasspathSince; 151 152 /** 153 * SDK version this library was removed from the BOOTCLASSPATH. 154 * 155 * <p>At the SDK level specified in this field and higher, this library needs to be 156 * explicitly added by apps. For compatibility reasons, when an app 157 * targets an SDK less than the value of this attribute, this library is automatically 158 * added. 159 * 160 * <p>0 means not specified. 161 */ 162 public final String onBootclasspathBefore; 163 164 /** 165 * Declares whether this library can be safely ignored from <uses-library> tags. 166 * 167 * <p> This can happen if the library initially had to be explicitly depended-on using that 168 * tag but has since been moved to the BOOTCLASSPATH which means now is always available 169 * and the tag is no longer required. 170 */ 171 public final boolean canBeSafelyIgnored; 172 173 public final boolean isNative; 174 175 176 @VisibleForTesting SharedLibraryEntry(String name, String filename, String[] dependencies, boolean isNative)177 public SharedLibraryEntry(String name, String filename, String[] dependencies, 178 boolean isNative) { 179 this(name, filename, dependencies, null /* onBootclasspathSince */, 180 null /* onBootclasspathBefore */, isNative); 181 } 182 183 @VisibleForTesting SharedLibraryEntry(String name, String filename, String[] dependencies, String onBootclasspathSince, String onBootclasspathBefore)184 public SharedLibraryEntry(String name, String filename, String[] dependencies, 185 String onBootclasspathSince, String onBootclasspathBefore) { 186 this(name, filename, dependencies, onBootclasspathSince, onBootclasspathBefore, 187 false /* isNative */); 188 } 189 SharedLibraryEntry(String name, String filename, String[] dependencies, String onBootclasspathSince, String onBootclasspathBefore, boolean isNative)190 SharedLibraryEntry(String name, String filename, String[] dependencies, 191 String onBootclasspathSince, String onBootclasspathBefore, boolean isNative) { 192 this.name = name; 193 this.filename = filename; 194 this.dependencies = dependencies; 195 this.onBootclasspathSince = onBootclasspathSince; 196 this.onBootclasspathBefore = onBootclasspathBefore; 197 this.isNative = isNative; 198 199 // this entry can be ignored if either: 200 // - onBootclasspathSince is set and we are at or past that SDK 201 // - onBootclasspathBefore is set and we are before that SDK 202 canBeSafelyIgnored = 203 (this.onBootclasspathSince != null 204 && isAtLeastSdkLevel(this.onBootclasspathSince)) 205 || (this.onBootclasspathBefore != null 206 && !isAtLeastSdkLevel(this.onBootclasspathBefore)); 207 } 208 } 209 210 // These are the built-in shared libraries that were read from the 211 // system configuration files. Keys are the library names; values are 212 // the individual entries that contain information such as filename 213 // and dependencies. 214 final ArrayMap<String, SharedLibraryEntry> mSharedLibraries = new ArrayMap<>(); 215 216 // These are the features this devices supports that were read from the 217 // system configuration files. 218 final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>(); 219 220 // These are the features which this device doesn't support; the OEM 221 // partition uses these to opt-out of features from the system image. 222 final ArraySet<String> mUnavailableFeatures = new ArraySet<>(); 223 224 public static final class PermissionEntry { 225 public final String name; 226 public int[] gids; 227 public boolean perUser; 228 PermissionEntry(String name, boolean perUser)229 PermissionEntry(String name, boolean perUser) { 230 this.name = name; 231 this.perUser = perUser; 232 } 233 } 234 235 // These are the permission -> gid mappings that were read from the 236 // system configuration files. 237 final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>(); 238 239 // These are the packages that are white-listed to be able to run in the 240 // background while in power save mode (but not whitelisted from device idle modes), 241 // as read from the configuration files. 242 final ArraySet<String> mAllowInPowerSaveExceptIdle = new ArraySet<>(); 243 244 // These are the packages that are white-listed to be able to run in the 245 // background while in power save mode, as read from the configuration files. 246 final ArraySet<String> mAllowInPowerSave = new ArraySet<>(); 247 248 // These are the packages that are white-listed to be able to run in the 249 // background while in data-usage save mode, as read from the configuration files. 250 final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>(); 251 252 // These are the packages that are white-listed to be able to run background location 253 // without throttling, as read from the configuration files. 254 final ArraySet<String> mAllowUnthrottledLocation = new ArraySet<>(); 255 256 // These are the packages that are allow-listed to be able to retrieve location when 257 // the location state is driver assistance only. 258 final ArrayMap<String, ArraySet<String>> mAllowAdasSettings = new ArrayMap<>(); 259 260 // These are the packages that are white-listed to be able to retrieve location even when user 261 // location settings are off, for emergency purposes, as read from the configuration files. 262 final ArrayMap<String, ArraySet<String>> mAllowIgnoreLocationSettings = new ArrayMap<>(); 263 264 // These are the action strings of broadcasts which are whitelisted to 265 // be delivered anonymously even to apps which target O+. 266 final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>(); 267 268 // These are the packages that are exempted from the background restriction applied 269 // by the system automatically, i.e., due to high background current drain. 270 final ArraySet<String> mBgRestrictionExemption = new ArraySet<>(); 271 272 // These are the package names of apps which should be automatically granted domain verification 273 // for all of their domains. The only way these apps can be overridden by the user is by 274 // explicitly disabling overall link handling support in app info. 275 final ArraySet<String> mLinkedApps = new ArraySet<>(); 276 277 // These are the components that are enabled by default as VR mode listener services. 278 final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>(); 279 280 // These are the permitted backup transport service components 281 final ArraySet<ComponentName> mBackupTransportWhitelist = new ArraySet<>(); 282 283 // These are packages mapped to maps of component class name to default enabled state. 284 final ArrayMap<String, ArrayMap<String, Boolean>> mPackageComponentEnabledState = 285 new ArrayMap<>(); 286 287 // Package names that are exempted from private API blacklisting 288 final ArraySet<String> mHiddenApiPackageWhitelist = new ArraySet<>(); 289 290 // The list of carrier applications which should be disabled until used. 291 // This function suppresses update notifications for these pre-installed apps. 292 // In SubscriptionInfoUpdater, the listed applications are disabled until used when all of the 293 // following conditions are met. 294 // 1. Not currently carrier-privileged according to the inserted SIM 295 // 2. Pre-installed 296 // 3. In the default state (enabled but not explicitly) 297 // And SubscriptionInfoUpdater undoes this and marks the app enabled when a SIM is inserted 298 // that marks the app as carrier privileged. It also grants the app default permissions 299 // for Phone and Location. As such, apps MUST only ever be added to this list if they 300 // obtain user consent to access their location through other means. 301 final ArraySet<String> mDisabledUntilUsedPreinstalledCarrierApps = new ArraySet<>(); 302 303 // These are the packages of carrier-associated apps which should be disabled until used until 304 // a SIM is inserted which grants carrier privileges to that carrier app. 305 final ArrayMap<String, List<CarrierAssociatedAppEntry>> 306 mDisabledUntilUsedPreinstalledCarrierAssociatedApps = new ArrayMap<>(); 307 308 private final PermissionAllowlist mPermissionAllowlist = new PermissionAllowlist(); 309 310 // Allowed associations between applications. If there are any entries 311 // for an app, those are the only associations allowed; otherwise, all associations 312 // are allowed. Allowing an association from app A to app B means app A can not 313 // associate with any other apps, but does not limit what apps B can associate with. 314 final ArrayMap<String, ArraySet<String>> mAllowedAssociations = new ArrayMap<>(); 315 316 private final ArraySet<String> mBugreportWhitelistedPackages = new ArraySet<>(); 317 private final ArraySet<String> mAppDataIsolationWhitelistedApps = new ArraySet<>(); 318 319 // Map of packagesNames to userTypes. Stored temporarily until cleared by UserManagerService(). 320 private ArrayMap<String, Set<String>> mPackageToUserTypeWhitelist = new ArrayMap<>(); 321 private ArrayMap<String, Set<String>> mPackageToUserTypeBlacklist = new ArrayMap<>(); 322 323 private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>(); 324 private final ArraySet<String> mAutomaticRollbackDenylistedPackages = new ArraySet<>(); 325 private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>(); 326 // A map from package name of vendor APEXes that can be updated to an installer package name 327 // allowed to install updates for it. 328 private final ArrayMap<String, String> mAllowedVendorApexes = new ArrayMap<>(); 329 // A set of package names that are allowed to use <install-constraints> manifest tag. 330 private final Set<String> mInstallConstraintsAllowlist = new ArraySet<>(); 331 332 private String mModulesInstallerPackageName; 333 // Update ownership for system applications and the installers eligible to update them. 334 private final ArrayMap<String, String> mUpdateOwnersForSystemApps = new ArrayMap<>(); 335 336 // Set of package names that should not be marked as "stopped" during initial device boot 337 // or when adding a new user. A new package not contained in this set will be 338 // marked as stopped by the system 339 @NonNull private final Set<String> mInitialNonStoppedSystemPackages = new ArraySet<>(); 340 341 // A map of preloaded package names and the path to its app metadata file path. 342 private final ArrayMap<String, String> mAppMetadataFilePaths = new ArrayMap<>(); 343 344 /** 345 * Map of system pre-defined, uniquely named actors; keys are namespace, 346 * value maps actor name to package name. 347 */ 348 private Map<String, Map<String, String>> mNamedActors = null; 349 350 // Package name of the package pre-installed on a read-only 351 // partition that is used to verify if an overlay package fulfills 352 // the 'config_signature' policy by comparing their signatures: 353 // if the overlay package is signed with the same certificate as 354 // the package declared in 'overlay-config-signature' tag, then the 355 // overlay package fulfills the 'config_signature' policy. 356 private String mOverlayConfigSignaturePackage; 357 getInstance()358 public static SystemConfig getInstance() { 359 if (!isSystemProcess()) { 360 Slog.wtf(TAG, "SystemConfig is being accessed by a process other than " 361 + "system_server."); 362 } 363 364 synchronized (SystemConfig.class) { 365 if (sInstance == null) { 366 sInstance = new SystemConfig(); 367 } 368 return sInstance; 369 } 370 } 371 getGlobalGids()372 public int[] getGlobalGids() { 373 return mGlobalGids; 374 } 375 getSystemPermissions()376 public SparseArray<ArraySet<String>> getSystemPermissions() { 377 return mSystemPermissions; 378 } 379 getSplitPermissions()380 public ArrayList<SplitPermissionInfo> getSplitPermissions() { 381 return mSplitPermissions; 382 } 383 getSharedLibraries()384 public ArrayMap<String, SharedLibraryEntry> getSharedLibraries() { 385 return mSharedLibraries; 386 } 387 getAvailableFeatures()388 public ArrayMap<String, FeatureInfo> getAvailableFeatures() { 389 return mAvailableFeatures; 390 } 391 getPermissions()392 public ArrayMap<String, PermissionEntry> getPermissions() { 393 return mPermissions; 394 } 395 getAllowImplicitBroadcasts()396 public ArraySet<String> getAllowImplicitBroadcasts() { 397 return mAllowImplicitBroadcasts; 398 } 399 getAllowInPowerSaveExceptIdle()400 public ArraySet<String> getAllowInPowerSaveExceptIdle() { 401 return mAllowInPowerSaveExceptIdle; 402 } 403 getAllowInPowerSave()404 public ArraySet<String> getAllowInPowerSave() { 405 return mAllowInPowerSave; 406 } 407 getAllowInDataUsageSave()408 public ArraySet<String> getAllowInDataUsageSave() { 409 return mAllowInDataUsageSave; 410 } 411 getAllowUnthrottledLocation()412 public ArraySet<String> getAllowUnthrottledLocation() { 413 return mAllowUnthrottledLocation; 414 } 415 getAllowAdasLocationSettings()416 public ArrayMap<String, ArraySet<String>> getAllowAdasLocationSettings() { 417 return mAllowAdasSettings; 418 } 419 getAllowIgnoreLocationSettings()420 public ArrayMap<String, ArraySet<String>> getAllowIgnoreLocationSettings() { 421 return mAllowIgnoreLocationSettings; 422 } 423 getBgRestrictionExemption()424 public ArraySet<String> getBgRestrictionExemption() { 425 return mBgRestrictionExemption; 426 } 427 getLinkedApps()428 public ArraySet<String> getLinkedApps() { 429 return mLinkedApps; 430 } 431 getHiddenApiWhitelistedApps()432 public ArraySet<String> getHiddenApiWhitelistedApps() { 433 return mHiddenApiPackageWhitelist; 434 } 435 getDefaultVrComponents()436 public ArraySet<ComponentName> getDefaultVrComponents() { 437 return mDefaultVrComponents; 438 } 439 getBackupTransportWhitelist()440 public ArraySet<ComponentName> getBackupTransportWhitelist() { 441 return mBackupTransportWhitelist; 442 } 443 getComponentsEnabledStates(String packageName)444 public ArrayMap<String, Boolean> getComponentsEnabledStates(String packageName) { 445 return mPackageComponentEnabledState.get(packageName); 446 } 447 getDisabledUntilUsedPreinstalledCarrierApps()448 public ArraySet<String> getDisabledUntilUsedPreinstalledCarrierApps() { 449 return mDisabledUntilUsedPreinstalledCarrierApps; 450 } 451 452 public ArrayMap<String, List<CarrierAssociatedAppEntry>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps()453 getDisabledUntilUsedPreinstalledCarrierAssociatedApps() { 454 return mDisabledUntilUsedPreinstalledCarrierAssociatedApps; 455 } 456 getPermissionAllowlist()457 public PermissionAllowlist getPermissionAllowlist() { 458 return mPermissionAllowlist; 459 } 460 getAllowedAssociations()461 public ArrayMap<String, ArraySet<String>> getAllowedAssociations() { 462 return mAllowedAssociations; 463 } 464 getBugreportWhitelistedPackages()465 public ArraySet<String> getBugreportWhitelistedPackages() { 466 return mBugreportWhitelistedPackages; 467 } 468 getRollbackWhitelistedPackages()469 public Set<String> getRollbackWhitelistedPackages() { 470 return mRollbackWhitelistedPackages; 471 } 472 getAutomaticRollbackDenylistedPackages()473 public Set<String> getAutomaticRollbackDenylistedPackages() { 474 return mAutomaticRollbackDenylistedPackages; 475 } 476 getWhitelistedStagedInstallers()477 public Set<String> getWhitelistedStagedInstallers() { 478 return mWhitelistedStagedInstallers; 479 } 480 getAllowedVendorApexes()481 public Map<String, String> getAllowedVendorApexes() { 482 return mAllowedVendorApexes; 483 } 484 getInstallConstraintsAllowlist()485 public Set<String> getInstallConstraintsAllowlist() { 486 return mInstallConstraintsAllowlist; 487 } 488 getModulesInstallerPackageName()489 public String getModulesInstallerPackageName() { 490 return mModulesInstallerPackageName; 491 } 492 493 /** 494 * Gets the update owner of the given package from "update-ownership" tags in sysconfig. 495 */ getSystemAppUpdateOwnerPackageName(@onNull String packageName)496 public @Nullable String getSystemAppUpdateOwnerPackageName(@NonNull String packageName) { 497 return mUpdateOwnersForSystemApps.get(packageName); 498 } 499 getAppDataIsolationWhitelistedApps()500 public ArraySet<String> getAppDataIsolationWhitelistedApps() { 501 return mAppDataIsolationWhitelistedApps; 502 } 503 504 /** 505 * Gets map of packagesNames to userTypes, dictating on which user types each package should be 506 * initially installed, and then removes this map from SystemConfig. 507 * Called by UserManagerService when it is constructed. 508 */ getAndClearPackageToUserTypeWhitelist()509 public ArrayMap<String, Set<String>> getAndClearPackageToUserTypeWhitelist() { 510 ArrayMap<String, Set<String>> r = mPackageToUserTypeWhitelist; 511 mPackageToUserTypeWhitelist = new ArrayMap<>(0); 512 return r; 513 } 514 515 /** 516 * Gets map of packagesNames to userTypes, dictating on which user types each package should NOT 517 * be initially installed, even if they are whitelisted, and then removes this map from 518 * SystemConfig. 519 * Called by UserManagerService when it is constructed. 520 */ getAndClearPackageToUserTypeBlacklist()521 public ArrayMap<String, Set<String>> getAndClearPackageToUserTypeBlacklist() { 522 ArrayMap<String, Set<String>> r = mPackageToUserTypeBlacklist; 523 mPackageToUserTypeBlacklist = new ArrayMap<>(0); 524 return r; 525 } 526 527 @NonNull getNamedActors()528 public Map<String, Map<String, String>> getNamedActors() { 529 return mNamedActors != null ? mNamedActors : Collections.emptyMap(); 530 } 531 532 @Nullable getOverlayConfigSignaturePackage()533 public String getOverlayConfigSignaturePackage() { 534 return TextUtils.isEmpty(mOverlayConfigSignaturePackage) 535 ? null : mOverlayConfigSignaturePackage; 536 } 537 getInitialNonStoppedSystemPackages()538 public Set<String> getInitialNonStoppedSystemPackages() { 539 return mInitialNonStoppedSystemPackages; 540 } 541 getAppMetadataFilePaths()542 public ArrayMap<String, String> getAppMetadataFilePaths() { 543 return mAppMetadataFilePaths; 544 } 545 546 /** 547 * Only use for testing. Do NOT use in production code. 548 * @param readPermissions false to create an empty SystemConfig; true to read the permissions. 549 */ 550 @VisibleForTesting SystemConfig(boolean readPermissions)551 public SystemConfig(boolean readPermissions) { 552 if (readPermissions) { 553 Slog.w(TAG, "Constructing a test SystemConfig"); 554 readAllPermissions(); 555 } else { 556 Slog.w(TAG, "Constructing an empty test SystemConfig"); 557 } 558 } 559 SystemConfig()560 SystemConfig() { 561 TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); 562 log.traceBegin("readAllPermissions"); 563 try { 564 readAllPermissions(); 565 readPublicNativeLibrariesList(); 566 } finally { 567 log.traceEnd(); 568 } 569 } 570 readAllPermissions()571 private void readAllPermissions() { 572 final XmlPullParser parser = Xml.newPullParser(); 573 574 // Read configuration from system 575 readPermissions(parser, Environment.buildPath( 576 Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL); 577 578 // Read configuration from the old permissions dir 579 readPermissions(parser, Environment.buildPath( 580 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL); 581 582 // Vendors are only allowed to customize these 583 int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS 584 | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX; 585 if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.O_MR1) { 586 // For backward compatibility 587 vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS); 588 } 589 readPermissions(parser, Environment.buildPath( 590 Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag); 591 readPermissions(parser, Environment.buildPath( 592 Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag); 593 594 String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, ""); 595 if (!vendorSkuProperty.isEmpty()) { 596 String vendorSkuDir = "sku_" + vendorSkuProperty; 597 readPermissions(parser, Environment.buildPath( 598 Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir), 599 vendorPermissionFlag); 600 readPermissions(parser, Environment.buildPath( 601 Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir), 602 vendorPermissionFlag); 603 } 604 605 // Allow ODM to customize system configs as much as Vendor, because /odm is another 606 // vendor partition other than /vendor. 607 int odmPermissionFlag = vendorPermissionFlag; 608 readPermissions(parser, Environment.buildPath( 609 Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag); 610 readPermissions(parser, Environment.buildPath( 611 Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag); 612 613 String skuProperty = SystemProperties.get(SKU_PROPERTY, ""); 614 if (!skuProperty.isEmpty()) { 615 String skuDir = "sku_" + skuProperty; 616 617 readPermissions(parser, Environment.buildPath( 618 Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag); 619 readPermissions(parser, Environment.buildPath( 620 Environment.getOdmDirectory(), "etc", "permissions", skuDir), 621 odmPermissionFlag); 622 } 623 624 // Allow OEM to customize these 625 int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS 626 | ALLOW_VENDOR_APEX; 627 readPermissions(parser, Environment.buildPath( 628 Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag); 629 readPermissions(parser, Environment.buildPath( 630 Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag); 631 632 // Allow Product to customize these configs 633 // TODO(b/157203468): ALLOW_HIDDENAPI_WHITELISTING must be removed because we prohibited 634 // the use of hidden APIs from the product partition. 635 int productPermissionFlag = ALLOW_FEATURES | ALLOW_LIBS | ALLOW_PERMISSIONS 636 | ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_HIDDENAPI_WHITELISTING 637 | ALLOW_ASSOCIATIONS | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS 638 | ALLOW_VENDOR_APEX; 639 if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.R) { 640 // TODO(b/157393157): This must check product interface enforcement instead of 641 // DEVICE_INITIAL_SDK_INT for the devices without product interface enforcement. 642 productPermissionFlag = ALLOW_ALL; 643 } 644 readPermissions(parser, Environment.buildPath( 645 Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag); 646 readPermissions(parser, Environment.buildPath( 647 Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag); 648 649 // Allow /system_ext to customize all system configs 650 readPermissions(parser, Environment.buildPath( 651 Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL); 652 readPermissions(parser, Environment.buildPath( 653 Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL); 654 655 // Skip loading configuration from apex if it is not a system process. 656 if (!isSystemProcess()) { 657 return; 658 } 659 // Read configuration of features, libs and priv-app permissions from apex module. 660 int apexPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS; 661 // TODO: Use a solid way to filter apex module folders? 662 for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) { 663 if (f.isFile() || f.getPath().contains("@")) { 664 continue; 665 } 666 readPermissions(parser, Environment.buildPath(f, "etc", "permissions"), 667 apexPermissionFlag); 668 } 669 } 670 671 @VisibleForTesting readPermissions(final XmlPullParser parser, File libraryDir, int permissionFlag)672 public void readPermissions(final XmlPullParser parser, File libraryDir, int permissionFlag) { 673 // Read permissions from given directory. 674 if (!libraryDir.exists() || !libraryDir.isDirectory()) { 675 if (permissionFlag == ALLOW_ALL) { 676 Slog.w(TAG, "No directory " + libraryDir + ", skipping"); 677 } 678 return; 679 } 680 if (!libraryDir.canRead()) { 681 Slog.w(TAG, "Directory " + libraryDir + " cannot be read"); 682 return; 683 } 684 685 // Iterate over the files in the directory and scan .xml files 686 File platformFile = null; 687 for (File f : libraryDir.listFiles()) { 688 if (!f.isFile()) { 689 continue; 690 } 691 692 // We'll read platform.xml last 693 if (f.getPath().endsWith("etc/permissions/platform.xml")) { 694 platformFile = f; 695 continue; 696 } 697 698 if (!f.getPath().endsWith(".xml")) { 699 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring"); 700 continue; 701 } 702 if (!f.canRead()) { 703 Slog.w(TAG, "Permissions library file " + f + " cannot be read"); 704 continue; 705 } 706 707 readPermissionsFromXml(parser, f, permissionFlag); 708 } 709 710 // Read platform permissions last so it will take precedence 711 if (platformFile != null) { 712 readPermissionsFromXml(parser, platformFile, permissionFlag); 713 } 714 } 715 logNotAllowedInPartition(String name, File permFile, XmlPullParser parser)716 private void logNotAllowedInPartition(String name, File permFile, XmlPullParser parser) { 717 Slog.w(TAG, "<" + name + "> not allowed in partition of " 718 + permFile + " at " + parser.getPositionDescription()); 719 } 720 readPermissionsFromXml(final XmlPullParser parser, File permFile, int permissionFlag)721 private void readPermissionsFromXml(final XmlPullParser parser, File permFile, 722 int permissionFlag) { 723 final FileReader permReader; 724 try { 725 permReader = new FileReader(permFile); 726 } catch (FileNotFoundException e) { 727 Slog.w(TAG, "Couldn't find or open permissions file " + permFile); 728 return; 729 } 730 Slog.i(TAG, "Reading permissions from " + permFile); 731 732 final boolean lowRam = ActivityManager.isLowRamDeviceStatic(); 733 734 try { 735 parser.setInput(permReader); 736 737 int type; 738 while ((type=parser.next()) != parser.START_TAG 739 && type != parser.END_DOCUMENT) { 740 ; 741 } 742 743 if (type != parser.START_TAG) { 744 throw new XmlPullParserException("No start tag found"); 745 } 746 747 if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) { 748 throw new XmlPullParserException("Unexpected start tag in " + permFile 749 + ": found " + parser.getName() + ", expected 'permissions' or 'config'"); 750 } 751 752 final boolean allowAll = permissionFlag == ALLOW_ALL; 753 final boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0; 754 final boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0; 755 final boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0; 756 final boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0; 757 final boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) 758 != 0; 759 final boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0; 760 final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) 761 != 0; 762 final boolean allowAssociations = (permissionFlag & ALLOW_ASSOCIATIONS) != 0; 763 final boolean allowOverrideAppRestrictions = 764 (permissionFlag & ALLOW_OVERRIDE_APP_RESTRICTIONS) != 0; 765 final boolean allowImplicitBroadcasts = (permissionFlag & ALLOW_IMPLICIT_BROADCASTS) 766 != 0; 767 final boolean allowVendorApex = (permissionFlag & ALLOW_VENDOR_APEX) != 0; 768 while (true) { 769 XmlUtils.nextElement(parser); 770 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { 771 break; 772 } 773 774 String name = parser.getName(); 775 if (name == null) { 776 XmlUtils.skipCurrentTag(parser); 777 continue; 778 } 779 switch (name) { 780 case "group": { 781 if (allowAll) { 782 String gidStr = parser.getAttributeValue(null, "gid"); 783 if (gidStr != null) { 784 int gid = android.os.Process.getGidForName(gidStr); 785 mGlobalGids = appendInt(mGlobalGids, gid); 786 } else { 787 Slog.w(TAG, "<" + name + "> without gid in " + permFile + " at " 788 + parser.getPositionDescription()); 789 } 790 } else { 791 logNotAllowedInPartition(name, permFile, parser); 792 } 793 XmlUtils.skipCurrentTag(parser); 794 } break; 795 case "permission": { 796 if (allowPermissions) { 797 String perm = parser.getAttributeValue(null, "name"); 798 if (perm == null) { 799 Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " 800 + parser.getPositionDescription()); 801 XmlUtils.skipCurrentTag(parser); 802 break; 803 } 804 perm = perm.intern(); 805 readPermission(parser, perm); 806 } else { 807 logNotAllowedInPartition(name, permFile, parser); 808 XmlUtils.skipCurrentTag(parser); 809 } 810 } break; 811 case "assign-permission": { 812 if (allowPermissions) { 813 String perm = parser.getAttributeValue(null, "name"); 814 if (perm == null) { 815 Slog.w(TAG, "<" + name + "> without name in " + permFile 816 + " at " + parser.getPositionDescription()); 817 XmlUtils.skipCurrentTag(parser); 818 break; 819 } 820 String uidStr = parser.getAttributeValue(null, "uid"); 821 if (uidStr == null) { 822 Slog.w(TAG, "<" + name + "> without uid in " + permFile 823 + " at " + parser.getPositionDescription()); 824 XmlUtils.skipCurrentTag(parser); 825 break; 826 } 827 int uid = Process.getUidForName(uidStr); 828 if (uid < 0) { 829 Slog.w(TAG, "<" + name + "> with unknown uid \"" 830 + uidStr + " in " + permFile + " at " 831 + parser.getPositionDescription()); 832 XmlUtils.skipCurrentTag(parser); 833 break; 834 } 835 perm = perm.intern(); 836 ArraySet<String> perms = mSystemPermissions.get(uid); 837 if (perms == null) { 838 perms = new ArraySet<String>(); 839 mSystemPermissions.put(uid, perms); 840 } 841 perms.add(perm); 842 } else { 843 logNotAllowedInPartition(name, permFile, parser); 844 } 845 XmlUtils.skipCurrentTag(parser); 846 } break; 847 case "split-permission": { 848 if (allowPermissions) { 849 readSplitPermission(parser, permFile); 850 } else { 851 logNotAllowedInPartition(name, permFile, parser); 852 XmlUtils.skipCurrentTag(parser); 853 } 854 } break; 855 case "apex-library": 856 // "apex-library" is meant to behave exactly like "library" 857 case "library": { 858 if (allowLibs) { 859 String lname = parser.getAttributeValue(null, "name"); 860 String lfile = parser.getAttributeValue(null, "file"); 861 String ldependency = parser.getAttributeValue(null, "dependency"); 862 String minDeviceSdk = parser.getAttributeValue(null, "min-device-sdk"); 863 String maxDeviceSdk = parser.getAttributeValue(null, "max-device-sdk"); 864 if (lname == null) { 865 Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " 866 + parser.getPositionDescription()); 867 } else if (lfile == null) { 868 Slog.w(TAG, "<" + name + "> without file in " + permFile + " at " 869 + parser.getPositionDescription()); 870 } else { 871 boolean allowedMinSdk = 872 minDeviceSdk == null || isAtLeastSdkLevel(minDeviceSdk); 873 boolean allowedMaxSdk = 874 maxDeviceSdk == null || isAtMostSdkLevel(maxDeviceSdk); 875 final boolean exists = new File(lfile).exists(); 876 if (allowedMinSdk && allowedMaxSdk && exists) { 877 String bcpSince = parser.getAttributeValue(null, 878 "on-bootclasspath-since"); 879 String bcpBefore = parser.getAttributeValue(null, 880 "on-bootclasspath-before"); 881 SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, 882 ldependency == null 883 ? new String[0] : ldependency.split(":"), 884 bcpSince, bcpBefore); 885 mSharedLibraries.put(lname, entry); 886 } else { 887 final StringBuilder msg = new StringBuilder( 888 "Ignore shared library ").append(lname).append(":"); 889 if (!allowedMinSdk) { 890 msg.append(" min-device-sdk=").append(minDeviceSdk); 891 } 892 if (!allowedMaxSdk) { 893 msg.append(" max-device-sdk=").append(maxDeviceSdk); 894 } 895 if (!exists) { 896 msg.append(" ").append(lfile).append(" does not exist"); 897 } 898 Slog.i(TAG, msg.toString()); 899 } 900 } 901 } else { 902 logNotAllowedInPartition(name, permFile, parser); 903 } 904 XmlUtils.skipCurrentTag(parser); 905 } break; 906 case "feature": { 907 if (allowFeatures) { 908 String fname = parser.getAttributeValue(null, "name"); 909 int fversion = XmlUtils.readIntAttribute(parser, "version", 0); 910 boolean allowed; 911 if (!lowRam) { 912 allowed = true; 913 } else { 914 String notLowRam = parser.getAttributeValue(null, "notLowRam"); 915 allowed = !"true".equals(notLowRam); 916 } 917 if (fname == null) { 918 Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " 919 + parser.getPositionDescription()); 920 } else if (allowed) { 921 addFeature(fname, fversion); 922 } 923 } else { 924 logNotAllowedInPartition(name, permFile, parser); 925 } 926 XmlUtils.skipCurrentTag(parser); 927 } break; 928 case "unavailable-feature": { 929 if (allowFeatures) { 930 String fname = parser.getAttributeValue(null, "name"); 931 if (fname == null) { 932 Slog.w(TAG, "<" + name + "> without name in " + permFile 933 + " at " + parser.getPositionDescription()); 934 } else { 935 mUnavailableFeatures.add(fname); 936 } 937 } else { 938 logNotAllowedInPartition(name, permFile, parser); 939 } 940 XmlUtils.skipCurrentTag(parser); 941 } break; 942 case "allow-in-power-save-except-idle": { 943 if (allowOverrideAppRestrictions) { 944 String pkgname = parser.getAttributeValue(null, "package"); 945 if (pkgname == null) { 946 Slog.w(TAG, "<" + name + "> without package in " 947 + permFile + " at " + parser.getPositionDescription()); 948 } else { 949 mAllowInPowerSaveExceptIdle.add(pkgname); 950 } 951 } else { 952 logNotAllowedInPartition(name, permFile, parser); 953 } 954 XmlUtils.skipCurrentTag(parser); 955 } break; 956 case "allow-in-power-save": { 957 if (allowOverrideAppRestrictions) { 958 String pkgname = parser.getAttributeValue(null, "package"); 959 if (pkgname == null) { 960 Slog.w(TAG, "<" + name + "> without package in " 961 + permFile + " at " + parser.getPositionDescription()); 962 } else { 963 mAllowInPowerSave.add(pkgname); 964 } 965 } else { 966 logNotAllowedInPartition(name, permFile, parser); 967 } 968 XmlUtils.skipCurrentTag(parser); 969 } break; 970 case "allow-in-data-usage-save": { 971 if (allowOverrideAppRestrictions) { 972 String pkgname = parser.getAttributeValue(null, "package"); 973 if (pkgname == null) { 974 Slog.w(TAG, "<" + name + "> without package in " 975 + permFile + " at " + parser.getPositionDescription()); 976 } else { 977 mAllowInDataUsageSave.add(pkgname); 978 } 979 } else { 980 logNotAllowedInPartition(name, permFile, parser); 981 } 982 XmlUtils.skipCurrentTag(parser); 983 } break; 984 case "allow-unthrottled-location": { 985 if (allowOverrideAppRestrictions) { 986 String pkgname = parser.getAttributeValue(null, "package"); 987 if (pkgname == null) { 988 Slog.w(TAG, "<" + name + "> without package in " 989 + permFile + " at " + parser.getPositionDescription()); 990 } else { 991 mAllowUnthrottledLocation.add(pkgname); 992 } 993 } else { 994 logNotAllowedInPartition(name, permFile, parser); 995 } 996 XmlUtils.skipCurrentTag(parser); 997 } break; 998 case "allow-adas-location-settings" : { 999 if (allowOverrideAppRestrictions) { 1000 String pkgname = parser.getAttributeValue(null, "package"); 1001 String attributionTag = parser.getAttributeValue(null, 1002 "attributionTag"); 1003 if (pkgname == null) { 1004 Slog.w(TAG, "<" + name + "> without package in " 1005 + permFile + " at " + parser.getPositionDescription()); 1006 } else { 1007 ArraySet<String> tags = mAllowAdasSettings.get(pkgname); 1008 if (tags == null || !tags.isEmpty()) { 1009 if (tags == null) { 1010 tags = new ArraySet<>(1); 1011 mAllowAdasSettings.put(pkgname, tags); 1012 } 1013 if (!"*".equals(attributionTag)) { 1014 if ("null".equals(attributionTag)) { 1015 attributionTag = null; 1016 } 1017 tags.add(attributionTag); 1018 } 1019 } 1020 } 1021 } else { 1022 logNotAllowedInPartition(name, permFile, parser); 1023 } 1024 XmlUtils.skipCurrentTag(parser); 1025 } break; 1026 case "allow-ignore-location-settings": { 1027 if (allowOverrideAppRestrictions) { 1028 String pkgname = parser.getAttributeValue(null, "package"); 1029 String attributionTag = parser.getAttributeValue(null, 1030 "attributionTag"); 1031 if (pkgname == null) { 1032 Slog.w(TAG, "<" + name + "> without package in " 1033 + permFile + " at " + parser.getPositionDescription()); 1034 } else { 1035 ArraySet<String> tags = mAllowIgnoreLocationSettings.get(pkgname); 1036 if (tags == null || !tags.isEmpty()) { 1037 if (tags == null) { 1038 tags = new ArraySet<>(1); 1039 mAllowIgnoreLocationSettings.put(pkgname, tags); 1040 } 1041 if (!"*".equals(attributionTag)) { 1042 if ("null".equals(attributionTag)) { 1043 attributionTag = null; 1044 } 1045 tags.add(attributionTag); 1046 } 1047 } 1048 } 1049 } else { 1050 logNotAllowedInPartition(name, permFile, parser); 1051 } 1052 XmlUtils.skipCurrentTag(parser); 1053 } break; 1054 case "allow-implicit-broadcast": { 1055 if (allowImplicitBroadcasts) { 1056 String action = parser.getAttributeValue(null, "action"); 1057 if (action == null) { 1058 Slog.w(TAG, "<" + name + "> without action in " 1059 + permFile + " at " + parser.getPositionDescription()); 1060 } else { 1061 mAllowImplicitBroadcasts.add(action); 1062 } 1063 } else { 1064 logNotAllowedInPartition(name, permFile, parser); 1065 } 1066 XmlUtils.skipCurrentTag(parser); 1067 } break; 1068 case "app-link": { 1069 if (allowAppConfigs) { 1070 String pkgname = parser.getAttributeValue(null, "package"); 1071 if (pkgname == null) { 1072 Slog.w(TAG, "<" + name + "> without package in " + permFile 1073 + " at " + parser.getPositionDescription()); 1074 } else { 1075 mLinkedApps.add(pkgname); 1076 } 1077 } else { 1078 logNotAllowedInPartition(name, permFile, parser); 1079 } 1080 XmlUtils.skipCurrentTag(parser); 1081 } break; 1082 case "bg-restriction-exemption": { 1083 if (allowOverrideAppRestrictions) { 1084 String pkgname = parser.getAttributeValue(null, "package"); 1085 if (pkgname == null) { 1086 Slog.w(TAG, "<" + name + "> without package in " 1087 + permFile + " at " + parser.getPositionDescription()); 1088 } else { 1089 mBgRestrictionExemption.add(pkgname); 1090 } 1091 } else { 1092 logNotAllowedInPartition(name, permFile, parser); 1093 } 1094 XmlUtils.skipCurrentTag(parser); 1095 } break; 1096 case "default-enabled-vr-app": { 1097 if (allowAppConfigs) { 1098 String pkgname = parser.getAttributeValue(null, "package"); 1099 String clsname = parser.getAttributeValue(null, "class"); 1100 if (pkgname == null) { 1101 Slog.w(TAG, "<" + name + "> without package in " 1102 + permFile + " at " + parser.getPositionDescription()); 1103 } else if (clsname == null) { 1104 Slog.w(TAG, "<" + name + "> without class in " 1105 + permFile + " at " + parser.getPositionDescription()); 1106 } else { 1107 mDefaultVrComponents.add(new ComponentName(pkgname, clsname)); 1108 } 1109 } else { 1110 logNotAllowedInPartition(name, permFile, parser); 1111 } 1112 XmlUtils.skipCurrentTag(parser); 1113 } break; 1114 case "component-override": { 1115 readComponentOverrides(parser, permFile); 1116 } break; 1117 case "backup-transport-whitelisted-service": { 1118 if (allowFeatures) { 1119 String serviceName = parser.getAttributeValue(null, "service"); 1120 if (serviceName == null) { 1121 Slog.w(TAG, "<" + name + "> without service in " 1122 + permFile + " at " + parser.getPositionDescription()); 1123 } else { 1124 ComponentName cn = ComponentName.unflattenFromString(serviceName); 1125 if (cn == null) { 1126 Slog.w(TAG, "<" + name + "> with invalid service name " 1127 + serviceName + " in " + permFile 1128 + " at " + parser.getPositionDescription()); 1129 } else { 1130 mBackupTransportWhitelist.add(cn); 1131 } 1132 } 1133 } else { 1134 logNotAllowedInPartition(name, permFile, parser); 1135 } 1136 XmlUtils.skipCurrentTag(parser); 1137 } break; 1138 case "disabled-until-used-preinstalled-carrier-associated-app": { 1139 if (allowAppConfigs) { 1140 String pkgname = parser.getAttributeValue(null, "package"); 1141 String carrierPkgname = parser.getAttributeValue(null, 1142 "carrierAppPackage"); 1143 if (pkgname == null || carrierPkgname == null) { 1144 Slog.w(TAG, "<" + name 1145 + "> without package or carrierAppPackage in " + permFile 1146 + " at " + parser.getPositionDescription()); 1147 } else { 1148 // APKs added to system images via OTA should specify the addedInSdk 1149 // attribute, otherwise they may be enabled-by-default in too many 1150 // cases. See CarrierAppUtils for more info. 1151 int addedInSdk = CarrierAssociatedAppEntry.SDK_UNSPECIFIED; 1152 String addedInSdkStr = parser.getAttributeValue(null, "addedInSdk"); 1153 if (!TextUtils.isEmpty(addedInSdkStr)) { 1154 try { 1155 addedInSdk = Integer.parseInt(addedInSdkStr); 1156 } catch (NumberFormatException e) { 1157 Slog.w(TAG, "<" + name + "> addedInSdk not an integer in " 1158 + permFile + " at " 1159 + parser.getPositionDescription()); 1160 XmlUtils.skipCurrentTag(parser); 1161 break; 1162 } 1163 } 1164 List<CarrierAssociatedAppEntry> associatedPkgs = 1165 mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get( 1166 carrierPkgname); 1167 if (associatedPkgs == null) { 1168 associatedPkgs = new ArrayList<>(); 1169 mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put( 1170 carrierPkgname, associatedPkgs); 1171 } 1172 associatedPkgs.add( 1173 new CarrierAssociatedAppEntry(pkgname, addedInSdk)); 1174 } 1175 } else { 1176 logNotAllowedInPartition(name, permFile, parser); 1177 } 1178 XmlUtils.skipCurrentTag(parser); 1179 } break; 1180 case "disabled-until-used-preinstalled-carrier-app": { 1181 if (allowAppConfigs) { 1182 String pkgname = parser.getAttributeValue(null, "package"); 1183 if (pkgname == null) { 1184 Slog.w(TAG, 1185 "<" + name + "> without " 1186 + "package in " + permFile + " at " 1187 + parser.getPositionDescription()); 1188 } else { 1189 mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname); 1190 } 1191 } else { 1192 logNotAllowedInPartition(name, permFile, parser); 1193 } 1194 XmlUtils.skipCurrentTag(parser); 1195 } break; 1196 case "privapp-permissions": { 1197 if (allowPrivappPermissions) { 1198 // privapp permissions from system, apex, vendor, product and 1199 // system_ext partitions are stored separately. This is to 1200 // prevent xml files in the vendor partition from granting 1201 // permissions to priv apps in the system partition and vice versa. 1202 boolean vendor = permFile.toPath().startsWith( 1203 Environment.getVendorDirectory().toPath() + "/") 1204 || permFile.toPath().startsWith( 1205 Environment.getOdmDirectory().toPath() + "/"); 1206 boolean product = permFile.toPath().startsWith( 1207 Environment.getProductDirectory().toPath() + "/"); 1208 boolean systemExt = permFile.toPath().startsWith( 1209 Environment.getSystemExtDirectory().toPath() + "/"); 1210 boolean apex = permFile.toPath().startsWith( 1211 Environment.getApexDirectory().toPath() + "/") 1212 && ApexProperties.updatable().orElse(false); 1213 if (vendor) { 1214 readPrivAppPermissions(parser, 1215 mPermissionAllowlist.getVendorPrivilegedAppAllowlist()); 1216 } else if (product) { 1217 readPrivAppPermissions(parser, 1218 mPermissionAllowlist.getProductPrivilegedAppAllowlist()); 1219 } else if (systemExt) { 1220 readPrivAppPermissions(parser, 1221 mPermissionAllowlist.getSystemExtPrivilegedAppAllowlist()); 1222 } else if (apex) { 1223 readApexPrivAppPermissions(parser, permFile, 1224 Environment.getApexDirectory().toPath()); 1225 } else { 1226 readPrivAppPermissions(parser, 1227 mPermissionAllowlist.getPrivilegedAppAllowlist()); 1228 } 1229 } else { 1230 logNotAllowedInPartition(name, permFile, parser); 1231 XmlUtils.skipCurrentTag(parser); 1232 } 1233 } break; 1234 case "oem-permissions": { 1235 if (allowOemPermissions) { 1236 readOemPermissions(parser); 1237 } else { 1238 logNotAllowedInPartition(name, permFile, parser); 1239 XmlUtils.skipCurrentTag(parser); 1240 } 1241 } break; 1242 case "hidden-api-whitelisted-app": { 1243 if (allowApiWhitelisting) { 1244 String pkgname = parser.getAttributeValue(null, "package"); 1245 if (pkgname == null) { 1246 Slog.w(TAG, "<" + name + "> without package in " 1247 + permFile + " at " + parser.getPositionDescription()); 1248 } else { 1249 mHiddenApiPackageWhitelist.add(pkgname); 1250 } 1251 } else { 1252 logNotAllowedInPartition(name, permFile, parser); 1253 } 1254 XmlUtils.skipCurrentTag(parser); 1255 } break; 1256 case "allow-association": { 1257 if (allowAssociations) { 1258 String target = parser.getAttributeValue(null, "target"); 1259 if (target == null) { 1260 Slog.w(TAG, "<" + name + "> without target in " + permFile 1261 + " at " + parser.getPositionDescription()); 1262 XmlUtils.skipCurrentTag(parser); 1263 break; 1264 } 1265 String allowed = parser.getAttributeValue(null, "allowed"); 1266 if (allowed == null) { 1267 Slog.w(TAG, "<" + name + "> without allowed in " + permFile 1268 + " at " + parser.getPositionDescription()); 1269 XmlUtils.skipCurrentTag(parser); 1270 break; 1271 } 1272 target = target.intern(); 1273 allowed = allowed.intern(); 1274 ArraySet<String> associations = mAllowedAssociations.get(target); 1275 if (associations == null) { 1276 associations = new ArraySet<>(); 1277 mAllowedAssociations.put(target, associations); 1278 } 1279 Slog.i(TAG, "Adding association: " + target + " <- " + allowed); 1280 associations.add(allowed); 1281 } else { 1282 logNotAllowedInPartition(name, permFile, parser); 1283 } 1284 XmlUtils.skipCurrentTag(parser); 1285 } break; 1286 case "app-data-isolation-whitelisted-app": { 1287 String pkgname = parser.getAttributeValue(null, "package"); 1288 if (pkgname == null) { 1289 Slog.w(TAG, "<" + name + "> without package in " + permFile 1290 + " at " + parser.getPositionDescription()); 1291 } else { 1292 mAppDataIsolationWhitelistedApps.add(pkgname); 1293 } 1294 XmlUtils.skipCurrentTag(parser); 1295 } break; 1296 case "bugreport-whitelisted": { 1297 String pkgname = parser.getAttributeValue(null, "package"); 1298 if (pkgname == null) { 1299 Slog.w(TAG, "<" + name + "> without package in " + permFile 1300 + " at " + parser.getPositionDescription()); 1301 } else { 1302 mBugreportWhitelistedPackages.add(pkgname); 1303 } 1304 XmlUtils.skipCurrentTag(parser); 1305 } break; 1306 case "install-in-user-type": { 1307 // NB: We allow any directory permission to declare install-in-user-type. 1308 readInstallInUserType(parser, 1309 mPackageToUserTypeWhitelist, mPackageToUserTypeBlacklist); 1310 } break; 1311 case "named-actor": { 1312 String namespace = TextUtils.safeIntern( 1313 parser.getAttributeValue(null, "namespace")); 1314 String actorName = parser.getAttributeValue(null, "name"); 1315 String pkgName = TextUtils.safeIntern( 1316 parser.getAttributeValue(null, "package")); 1317 if (TextUtils.isEmpty(namespace)) { 1318 Slog.wtf(TAG, "<" + name + "> without namespace in " + permFile 1319 + " at " + parser.getPositionDescription()); 1320 } else if (TextUtils.isEmpty(actorName)) { 1321 Slog.wtf(TAG, "<" + name + "> without actor name in " + permFile 1322 + " at " + parser.getPositionDescription()); 1323 } else if (TextUtils.isEmpty(pkgName)) { 1324 Slog.wtf(TAG, "<" + name + "> without package name in " + permFile 1325 + " at " + parser.getPositionDescription()); 1326 } else if ("android".equalsIgnoreCase(namespace)) { 1327 throw new IllegalStateException("Defining " + actorName + " as " 1328 + pkgName + " for the android namespace is not allowed"); 1329 } else { 1330 if (mNamedActors == null) { 1331 mNamedActors = new ArrayMap<>(); 1332 } 1333 1334 Map<String, String> nameToPkgMap = mNamedActors.get(namespace); 1335 if (nameToPkgMap == null) { 1336 nameToPkgMap = new ArrayMap<>(); 1337 mNamedActors.put(namespace, nameToPkgMap); 1338 } else if (nameToPkgMap.containsKey(actorName)) { 1339 String existing = nameToPkgMap.get(actorName); 1340 throw new IllegalStateException("Duplicate actor definition for " 1341 + namespace + "/" + actorName 1342 + "; defined as both " + existing + " and " + pkgName); 1343 } 1344 1345 nameToPkgMap.put(actorName, pkgName); 1346 } 1347 XmlUtils.skipCurrentTag(parser); 1348 } break; 1349 case "overlay-config-signature": { 1350 if (allowAll) { 1351 String pkgName = parser.getAttributeValue(null, "package"); 1352 if (pkgName == null) { 1353 Slog.w(TAG, "<" + name + "> without package in " + permFile 1354 + " at " + parser.getPositionDescription()); 1355 } else { 1356 if (TextUtils.isEmpty(mOverlayConfigSignaturePackage)) { 1357 mOverlayConfigSignaturePackage = pkgName.intern(); 1358 } else { 1359 throw new IllegalStateException("Reference signature package " 1360 + "defined as both " 1361 + mOverlayConfigSignaturePackage 1362 + " and " + pkgName); 1363 } 1364 } 1365 } else { 1366 logNotAllowedInPartition(name, permFile, parser); 1367 } 1368 XmlUtils.skipCurrentTag(parser); 1369 } break; 1370 case "rollback-whitelisted-app": { 1371 String pkgname = parser.getAttributeValue(null, "package"); 1372 if (pkgname == null) { 1373 Slog.w(TAG, "<" + name + "> without package in " + permFile 1374 + " at " + parser.getPositionDescription()); 1375 } else { 1376 mRollbackWhitelistedPackages.add(pkgname); 1377 } 1378 XmlUtils.skipCurrentTag(parser); 1379 } break; 1380 case "automatic-rollback-denylisted-app": { 1381 String pkgname = parser.getAttributeValue(null, "package"); 1382 if (pkgname == null) { 1383 Slog.w(TAG, "<" + name + "> without package in " + permFile 1384 + " at " + parser.getPositionDescription()); 1385 } else { 1386 mAutomaticRollbackDenylistedPackages.add(pkgname); 1387 } 1388 XmlUtils.skipCurrentTag(parser); 1389 } break; 1390 case "whitelisted-staged-installer": { 1391 if (allowAppConfigs) { 1392 String pkgname = parser.getAttributeValue(null, "package"); 1393 boolean isModulesInstaller = XmlUtils.readBooleanAttribute( 1394 parser, "isModulesInstaller", false); 1395 if (pkgname == null) { 1396 Slog.w(TAG, "<" + name + "> without package in " + permFile 1397 + " at " + parser.getPositionDescription()); 1398 } else { 1399 mWhitelistedStagedInstallers.add(pkgname); 1400 } 1401 if (isModulesInstaller) { 1402 if (mModulesInstallerPackageName != null) { 1403 throw new IllegalStateException( 1404 "Multiple modules installers"); 1405 } 1406 mModulesInstallerPackageName = pkgname; 1407 } 1408 } else { 1409 logNotAllowedInPartition(name, permFile, parser); 1410 } 1411 XmlUtils.skipCurrentTag(parser); 1412 } break; 1413 case "allowed-vendor-apex": { 1414 if (allowVendorApex) { 1415 String pkgName = parser.getAttributeValue(null, "package"); 1416 String installerPkgName = parser.getAttributeValue( 1417 null, "installerPackage"); 1418 if (pkgName == null) { 1419 Slog.w(TAG, "<" + name + "> without package in " + permFile 1420 + " at " + parser.getPositionDescription()); 1421 } 1422 if (installerPkgName == null) { 1423 Slog.w(TAG, "<" + name + "> without installerPackage in " + permFile 1424 + " at " + parser.getPositionDescription()); 1425 } 1426 if (pkgName != null && installerPkgName != null) { 1427 mAllowedVendorApexes.put(pkgName, installerPkgName); 1428 } 1429 } else { 1430 logNotAllowedInPartition(name, permFile, parser); 1431 } 1432 XmlUtils.skipCurrentTag(parser); 1433 } break; 1434 case "install-constraints-allowed": { 1435 if (allowAppConfigs) { 1436 String packageName = parser.getAttributeValue(null, "package"); 1437 if (packageName == null) { 1438 Slog.w(TAG, "<" + name + "> without package in " + permFile 1439 + " at " + parser.getPositionDescription()); 1440 } else { 1441 mInstallConstraintsAllowlist.add(packageName); 1442 } 1443 } else { 1444 logNotAllowedInPartition(name, permFile, parser); 1445 } 1446 XmlUtils.skipCurrentTag(parser); 1447 } break; 1448 case "update-ownership": { 1449 final String packageName = parser.getAttributeValue(null /* namespace */, 1450 "package"); 1451 final String installerName = parser.getAttributeValue(null /* namespace */, 1452 "installer"); 1453 if (TextUtils.isEmpty(packageName)) { 1454 Slog.w(TAG, "<" + name + "> without valid package in " + permFile 1455 + " at " + parser.getPositionDescription()); 1456 } else if (TextUtils.isEmpty(installerName)) { 1457 Slog.w(TAG, "<" + name + "> without valid installer in " + permFile 1458 + " at " + parser.getPositionDescription()); 1459 } else { 1460 mUpdateOwnersForSystemApps.put(packageName, installerName); 1461 } 1462 XmlUtils.skipCurrentTag(parser); 1463 } break; 1464 case "initial-package-state": { 1465 String pkgName = parser.getAttributeValue(null, "package"); 1466 String stopped = parser.getAttributeValue(null, "stopped"); 1467 if (TextUtils.isEmpty(pkgName)) { 1468 Slog.w(TAG, "<" + name + "> without package in " + permFile 1469 + " at " + parser.getPositionDescription()); 1470 } else if (TextUtils.isEmpty(stopped)) { 1471 Slog.w(TAG, "<" + name + "> without stopped in " + permFile 1472 + " at " + parser.getPositionDescription()); 1473 } else if (!Boolean.parseBoolean(stopped)) { 1474 mInitialNonStoppedSystemPackages.add(pkgName); 1475 } 1476 } break; 1477 case "asl-file": { 1478 String packageName = parser.getAttributeValue(null, "package"); 1479 String path = parser.getAttributeValue(null, "path"); 1480 if (TextUtils.isEmpty(packageName)) { 1481 Slog.w(TAG, "<" + name + "> without valid package in " + permFile 1482 + " at " + parser.getPositionDescription()); 1483 } else if (TextUtils.isEmpty(path)) { 1484 Slog.w(TAG, "<" + name + "> without valid path in " + permFile 1485 + " at " + parser.getPositionDescription()); 1486 } else { 1487 mAppMetadataFilePaths.put(packageName, path); 1488 } 1489 } break; 1490 default: { 1491 Slog.w(TAG, "Tag " + name + " is unknown in " 1492 + permFile + " at " + parser.getPositionDescription()); 1493 XmlUtils.skipCurrentTag(parser); 1494 } break; 1495 } 1496 } 1497 } catch (XmlPullParserException e) { 1498 Slog.w(TAG, "Got exception parsing permissions.", e); 1499 } catch (IOException e) { 1500 Slog.w(TAG, "Got exception parsing permissions.", e); 1501 } finally { 1502 IoUtils.closeQuietly(permReader); 1503 } 1504 1505 // Some devices can be field-converted to FBE, so offer to splice in 1506 // those features if not already defined by the static config 1507 if (StorageManager.isFileEncrypted()) { 1508 addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0); 1509 addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0); 1510 } 1511 1512 // Help legacy devices that may not have updated their static config 1513 if (StorageManager.hasAdoptable()) { 1514 addFeature(PackageManager.FEATURE_ADOPTABLE_STORAGE, 0); 1515 } 1516 1517 if (ActivityManager.isLowRamDeviceStatic()) { 1518 addFeature(PackageManager.FEATURE_RAM_LOW, 0); 1519 } else { 1520 addFeature(PackageManager.FEATURE_RAM_NORMAL, 0); 1521 } 1522 1523 final int incrementalVersion = IncrementalManager.getVersion(); 1524 if (incrementalVersion > 0) { 1525 addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, incrementalVersion); 1526 } 1527 1528 if (PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT) { 1529 addFeature(PackageManager.FEATURE_APP_ENUMERATION, 0); 1530 } 1531 1532 if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.Q) { 1533 addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0); 1534 } 1535 1536 enableIpSecTunnelMigrationOnVsrUAndAbove(); 1537 1538 if (isErofsSupported()) { 1539 if (isKernelVersionAtLeast(5, 10)) { 1540 addFeature(PackageManager.FEATURE_EROFS, 0); 1541 } else if (isKernelVersionAtLeast(4, 19)) { 1542 addFeature(PackageManager.FEATURE_EROFS_LEGACY, 0); 1543 } 1544 } 1545 1546 for (String featureName : mUnavailableFeatures) { 1547 removeFeature(featureName); 1548 } 1549 } 1550 1551 // This method only enables a new Android feature added in U and will not have impact on app 1552 // compatibility 1553 @SuppressWarnings("AndroidFrameworkCompatChange") enableIpSecTunnelMigrationOnVsrUAndAbove()1554 private void enableIpSecTunnelMigrationOnVsrUAndAbove() { 1555 final int vsrApi = 1556 SystemProperties.getInt( 1557 "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT); 1558 if (vsrApi > Build.VERSION_CODES.TIRAMISU) { 1559 addFeature(PackageManager.FEATURE_IPSEC_TUNNEL_MIGRATION, 0); 1560 } 1561 } 1562 addFeature(String name, int version)1563 private void addFeature(String name, int version) { 1564 FeatureInfo fi = mAvailableFeatures.get(name); 1565 if (fi == null) { 1566 fi = new FeatureInfo(); 1567 fi.name = name; 1568 fi.version = version; 1569 mAvailableFeatures.put(name, fi); 1570 } else { 1571 fi.version = Math.max(fi.version, version); 1572 } 1573 } 1574 removeFeature(String name)1575 private void removeFeature(String name) { 1576 if (mAvailableFeatures.remove(name) != null) { 1577 Slog.d(TAG, "Removed unavailable feature " + name); 1578 } 1579 } 1580 readPermission(XmlPullParser parser, String name)1581 void readPermission(XmlPullParser parser, String name) 1582 throws IOException, XmlPullParserException { 1583 if (mPermissions.containsKey(name)) { 1584 throw new IllegalStateException("Duplicate permission definition for " + name); 1585 } 1586 1587 final boolean perUser = XmlUtils.readBooleanAttribute(parser, "perUser", false); 1588 final PermissionEntry perm = new PermissionEntry(name, perUser); 1589 mPermissions.put(name, perm); 1590 1591 int outerDepth = parser.getDepth(); 1592 int type; 1593 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 1594 && (type != XmlPullParser.END_TAG 1595 || parser.getDepth() > outerDepth)) { 1596 if (type == XmlPullParser.END_TAG 1597 || type == XmlPullParser.TEXT) { 1598 continue; 1599 } 1600 1601 String tagName = parser.getName(); 1602 if ("group".equals(tagName)) { 1603 String gidStr = parser.getAttributeValue(null, "gid"); 1604 if (gidStr != null) { 1605 int gid = Process.getGidForName(gidStr); 1606 perm.gids = appendInt(perm.gids, gid); 1607 } else { 1608 Slog.w(TAG, "<group> without gid at " 1609 + parser.getPositionDescription()); 1610 } 1611 } 1612 XmlUtils.skipCurrentTag(parser); 1613 } 1614 } 1615 readPrivAppPermissions(@onNull XmlPullParser parser, @NonNull ArrayMap<String, ArrayMap<String, Boolean>> allowlist)1616 private void readPrivAppPermissions(@NonNull XmlPullParser parser, 1617 @NonNull ArrayMap<String, ArrayMap<String, Boolean>> allowlist) 1618 throws IOException, XmlPullParserException { 1619 readPermissionAllowlist(parser, allowlist, "privapp-permissions"); 1620 } 1621 readInstallInUserType(XmlPullParser parser, Map<String, Set<String>> doInstallMap, Map<String, Set<String>> nonInstallMap)1622 private void readInstallInUserType(XmlPullParser parser, 1623 Map<String, Set<String>> doInstallMap, 1624 Map<String, Set<String>> nonInstallMap) 1625 throws IOException, XmlPullParserException { 1626 final String packageName = parser.getAttributeValue(null, "package"); 1627 if (TextUtils.isEmpty(packageName)) { 1628 Slog.w(TAG, "package is required for <install-in-user-type> in " 1629 + parser.getPositionDescription()); 1630 return; 1631 } 1632 1633 Set<String> userTypesYes = doInstallMap.get(packageName); 1634 Set<String> userTypesNo = nonInstallMap.get(packageName); 1635 final int depth = parser.getDepth(); 1636 while (XmlUtils.nextElementWithin(parser, depth)) { 1637 final String name = parser.getName(); 1638 if ("install-in".equals(name)) { 1639 final String userType = parser.getAttributeValue(null, "user-type"); 1640 if (TextUtils.isEmpty(userType)) { 1641 Slog.w(TAG, "user-type is required for <install-in-user-type> in " 1642 + parser.getPositionDescription()); 1643 continue; 1644 } 1645 if (userTypesYes == null) { 1646 userTypesYes = new ArraySet<>(); 1647 doInstallMap.put(packageName, userTypesYes); 1648 } 1649 userTypesYes.add(userType); 1650 } else if ("do-not-install-in".equals(name)) { 1651 final String userType = parser.getAttributeValue(null, "user-type"); 1652 if (TextUtils.isEmpty(userType)) { 1653 Slog.w(TAG, "user-type is required for <install-in-user-type> in " 1654 + parser.getPositionDescription()); 1655 continue; 1656 } 1657 if (userTypesNo == null) { 1658 userTypesNo = new ArraySet<>(); 1659 nonInstallMap.put(packageName, userTypesNo); 1660 } 1661 userTypesNo.add(userType); 1662 } else { 1663 Slog.w(TAG, "unrecognized tag in <install-in-user-type> in " 1664 + parser.getPositionDescription()); 1665 } 1666 } 1667 } 1668 readOemPermissions(XmlPullParser parser)1669 void readOemPermissions(XmlPullParser parser) throws IOException, XmlPullParserException { 1670 readPermissionAllowlist(parser, mPermissionAllowlist.getOemAppAllowlist(), 1671 "oem-permissions"); 1672 } 1673 readPermissionAllowlist(@onNull XmlPullParser parser, @NonNull ArrayMap<String, ArrayMap<String, Boolean>> allowlist, @NonNull String tagName)1674 private static void readPermissionAllowlist(@NonNull XmlPullParser parser, 1675 @NonNull ArrayMap<String, ArrayMap<String, Boolean>> allowlist, @NonNull String tagName) 1676 throws IOException, XmlPullParserException { 1677 final String packageName = parser.getAttributeValue(null, "package"); 1678 if (TextUtils.isEmpty(packageName)) { 1679 Slog.w(TAG, "package is required for <" + tagName + "> in " 1680 + parser.getPositionDescription()); 1681 return; 1682 } 1683 1684 ArrayMap<String, Boolean> permissions = allowlist.get(packageName); 1685 if (permissions == null) { 1686 permissions = new ArrayMap<>(); 1687 } 1688 final int depth = parser.getDepth(); 1689 while (XmlUtils.nextElementWithin(parser, depth)) { 1690 final String name = parser.getName(); 1691 if ("permission".equals(name)) { 1692 final String permissionName = parser.getAttributeValue(null, "name"); 1693 if (TextUtils.isEmpty(permissionName)) { 1694 Slog.w(TAG, "name is required for <permission> in " 1695 + parser.getPositionDescription()); 1696 continue; 1697 } 1698 permissions.put(permissionName, Boolean.TRUE); 1699 } else if ("deny-permission".equals(name)) { 1700 String permissionName = parser.getAttributeValue(null, "name"); 1701 if (TextUtils.isEmpty(permissionName)) { 1702 Slog.w(TAG, "name is required for <deny-permission> in " 1703 + parser.getPositionDescription()); 1704 continue; 1705 } 1706 permissions.put(permissionName, Boolean.FALSE); 1707 } 1708 } 1709 allowlist.put(packageName, permissions); 1710 } 1711 readSplitPermission(XmlPullParser parser, File permFile)1712 private void readSplitPermission(XmlPullParser parser, File permFile) 1713 throws IOException, XmlPullParserException { 1714 String splitPerm = parser.getAttributeValue(null, "name"); 1715 if (splitPerm == null) { 1716 Slog.w(TAG, "<split-permission> without name in " + permFile + " at " 1717 + parser.getPositionDescription()); 1718 XmlUtils.skipCurrentTag(parser); 1719 return; 1720 } 1721 String targetSdkStr = parser.getAttributeValue(null, "targetSdk"); 1722 int targetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT + 1; 1723 if (!TextUtils.isEmpty(targetSdkStr)) { 1724 try { 1725 targetSdk = Integer.parseInt(targetSdkStr); 1726 } catch (NumberFormatException e) { 1727 Slog.w(TAG, "<split-permission> targetSdk not an integer in " + permFile + " at " 1728 + parser.getPositionDescription()); 1729 XmlUtils.skipCurrentTag(parser); 1730 return; 1731 } 1732 } 1733 final int depth = parser.getDepth(); 1734 List<String> newPermissions = new ArrayList<>(); 1735 while (XmlUtils.nextElementWithin(parser, depth)) { 1736 String name = parser.getName(); 1737 if ("new-permission".equals(name)) { 1738 final String newName = parser.getAttributeValue(null, "name"); 1739 if (TextUtils.isEmpty(newName)) { 1740 Slog.w(TAG, "name is required for <new-permission> in " 1741 + parser.getPositionDescription()); 1742 continue; 1743 } 1744 newPermissions.add(newName); 1745 } else { 1746 XmlUtils.skipCurrentTag(parser); 1747 } 1748 } 1749 if (!newPermissions.isEmpty()) { 1750 mSplitPermissions.add(new SplitPermissionInfo(splitPerm, newPermissions, targetSdk)); 1751 } 1752 } 1753 readComponentOverrides(XmlPullParser parser, File permFile)1754 private void readComponentOverrides(XmlPullParser parser, File permFile) 1755 throws IOException, XmlPullParserException { 1756 String pkgname = parser.getAttributeValue(null, "package"); 1757 if (pkgname == null) { 1758 Slog.w(TAG, "<component-override> without package in " 1759 + permFile + " at " + parser.getPositionDescription()); 1760 return; 1761 } 1762 1763 pkgname = pkgname.intern(); 1764 1765 final int depth = parser.getDepth(); 1766 while (XmlUtils.nextElementWithin(parser, depth)) { 1767 if ("component".equals(parser.getName())) { 1768 String clsname = parser.getAttributeValue(null, "class"); 1769 String enabled = parser.getAttributeValue(null, "enabled"); 1770 if (clsname == null) { 1771 Slog.w(TAG, "<component> without class in " 1772 + permFile + " at " + parser.getPositionDescription()); 1773 return; 1774 } else if (enabled == null) { 1775 Slog.w(TAG, "<component> without enabled in " 1776 + permFile + " at " + parser.getPositionDescription()); 1777 return; 1778 } 1779 1780 if (clsname.startsWith(".")) { 1781 clsname = pkgname + clsname; 1782 } 1783 1784 clsname = clsname.intern(); 1785 1786 ArrayMap<String, Boolean> componentEnabledStates = 1787 mPackageComponentEnabledState.get(pkgname); 1788 if (componentEnabledStates == null) { 1789 componentEnabledStates = new ArrayMap<>(); 1790 mPackageComponentEnabledState.put(pkgname, 1791 componentEnabledStates); 1792 } 1793 1794 componentEnabledStates.put(clsname, !"false".equals(enabled)); 1795 } 1796 } 1797 } 1798 readPublicNativeLibrariesList()1799 private void readPublicNativeLibrariesList() { 1800 readPublicLibrariesListFile(new File("/vendor/etc/public.libraries.txt")); 1801 String[] dirs = {"/system/etc", "/system_ext/etc", "/product/etc"}; 1802 for (String dir : dirs) { 1803 File[] files = new File(dir).listFiles(); 1804 if (files == null) { 1805 Slog.w(TAG, "Public libraries file folder missing: " + dir); 1806 continue; 1807 } 1808 for (File f : files) { 1809 String name = f.getName(); 1810 if (name.startsWith("public.libraries-") && name.endsWith(".txt")) { 1811 readPublicLibrariesListFile(f); 1812 } 1813 } 1814 } 1815 } 1816 readPublicLibrariesListFile(File listFile)1817 private void readPublicLibrariesListFile(File listFile) { 1818 try (BufferedReader br = new BufferedReader(new FileReader(listFile))) { 1819 String line; 1820 while ((line = br.readLine()) != null) { 1821 if (line.isEmpty() || line.startsWith("#")) { 1822 continue; 1823 } 1824 // Line format is <soname> [abi]. We take the soname part. 1825 String soname = line.trim().split(" ")[0]; 1826 SharedLibraryEntry entry = new SharedLibraryEntry( 1827 soname, soname, new String[0], true); 1828 mSharedLibraries.put(entry.name, entry); 1829 } 1830 } catch (IOException e) { 1831 Slog.w(TAG, "Failed to read public libraries file " + listFile, e); 1832 } 1833 } 1834 1835 1836 /** 1837 * Returns the module name for a file in the apex module's partition. 1838 */ getApexModuleNameFromFilePath(Path path, Path apexDirectoryPath)1839 private String getApexModuleNameFromFilePath(Path path, Path apexDirectoryPath) { 1840 if (!path.startsWith(apexDirectoryPath)) { 1841 throw new IllegalArgumentException("File " + path + " is not part of an APEX."); 1842 } 1843 // File must be in <apex_directory>/<module_name>/[extra_paths/]<xml_file> 1844 if (path.getNameCount() <= (apexDirectoryPath.getNameCount() + 1)) { 1845 throw new IllegalArgumentException("File " + path + " is in the APEX partition," 1846 + " but not inside a module."); 1847 } 1848 return path.getName(apexDirectoryPath.getNameCount()).toString(); 1849 } 1850 1851 /** 1852 * Reads the contents of the privileged permission allowlist stored inside an APEX. 1853 */ 1854 @VisibleForTesting readApexPrivAppPermissions(XmlPullParser parser, File permFile, Path apexDirectoryPath)1855 public void readApexPrivAppPermissions(XmlPullParser parser, File permFile, 1856 Path apexDirectoryPath) throws IOException, XmlPullParserException { 1857 final String moduleName = 1858 getApexModuleNameFromFilePath(permFile.toPath(), apexDirectoryPath); 1859 final ArrayMap<String, ArrayMap<String, ArrayMap<String, Boolean>>> allowlists = 1860 mPermissionAllowlist.getApexPrivilegedAppAllowlists(); 1861 ArrayMap<String, ArrayMap<String, Boolean>> allowlist = allowlists.get(moduleName); 1862 if (allowlist == null) { 1863 allowlist = new ArrayMap<>(); 1864 allowlists.put(moduleName, allowlist); 1865 } 1866 readPrivAppPermissions(parser, allowlist); 1867 } 1868 isSystemProcess()1869 private static boolean isSystemProcess() { 1870 return Process.myUid() == Process.SYSTEM_UID; 1871 } 1872 isErofsSupported()1873 private static boolean isErofsSupported() { 1874 try { 1875 final Path path = Paths.get("/sys/fs/erofs"); 1876 return Files.exists(path); 1877 } catch (Exception e) { 1878 return false; 1879 } 1880 } 1881 isKernelVersionAtLeast(int major, int minor)1882 private static boolean isKernelVersionAtLeast(int major, int minor) { 1883 final String kernelVersion = VintfRuntimeInfo.getKernelVersion(); 1884 final String[] parts = kernelVersion.split("\\."); 1885 if (parts.length < 2) { 1886 return false; 1887 } 1888 try { 1889 final int majorVersion = Integer.parseInt(parts[0]); 1890 final int minorVersion = Integer.parseInt(parts[1]); 1891 return majorVersion > major || (majorVersion == major && minorVersion >= minor); 1892 } catch (NumberFormatException e) { 1893 return false; 1894 } 1895 } 1896 } 1897