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