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