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