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