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