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.app.ActivityManager;
22 import android.content.ComponentName;
23 import android.content.pm.FeatureInfo;
24 import android.content.pm.PackageManager;
25 import android.os.Build;
26 import android.os.Environment;
27 import android.os.Process;
28 import android.os.SystemProperties;
29 import android.os.storage.StorageManager;
30 import android.permission.PermissionManager.SplitPermissionInfo;
31 import android.text.TextUtils;
32 import android.util.ArrayMap;
33 import android.util.ArraySet;
34 import android.util.Slog;
35 import android.util.SparseArray;
36 import android.util.Xml;
37 
38 import com.android.internal.util.XmlUtils;
39 
40 import libcore.io.IoUtils;
41 
42 import org.xmlpull.v1.XmlPullParser;
43 import org.xmlpull.v1.XmlPullParserException;
44 
45 import java.io.File;
46 import java.io.FileNotFoundException;
47 import java.io.FileReader;
48 import java.io.IOException;
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.List;
52 import java.util.Map;
53 
54 /**
55  * Loads global system configuration info.
56  */
57 public class SystemConfig {
58     static final String TAG = "SystemConfig";
59 
60     static SystemConfig sInstance;
61 
62     // permission flag, determines which types of configuration are allowed to be read
63     private static final int ALLOW_FEATURES = 0x01;
64     private static final int ALLOW_LIBS = 0x02;
65     private static final int ALLOW_PERMISSIONS = 0x04;
66     private static final int ALLOW_APP_CONFIGS = 0x08;
67     private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10;
68     private static final int ALLOW_OEM_PERMISSIONS = 0x20;
69     private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x40;
70     private static final int ALLOW_ASSOCIATIONS = 0x80;
71     private static final int ALLOW_ALL = ~0;
72 
73     // property for runtime configuration differentiation
74     private static final String SKU_PROPERTY = "ro.boot.product.hardware.sku";
75 
76     // Group-ids that are given to all packages as read from etc/permissions/*.xml.
77     int[] mGlobalGids;
78 
79     // These are the built-in uid -> permission mappings that were read from the
80     // system configuration files.
81     final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
82 
83     final ArrayList<SplitPermissionInfo> mSplitPermissions = new ArrayList<>();
84 
85     public static final class SharedLibraryEntry {
86         public final String name;
87         public final String filename;
88         public final String[] dependencies;
89 
SharedLibraryEntry(String name, String filename, String[] dependencies)90         SharedLibraryEntry(String name, String filename, String[] dependencies) {
91             this.name = name;
92             this.filename = filename;
93             this.dependencies = dependencies;
94         }
95     }
96 
97     // These are the built-in shared libraries that were read from the
98     // system configuration files. Keys are the library names; values are
99     // the individual entries that contain information such as filename
100     // and dependencies.
101     final ArrayMap<String, SharedLibraryEntry> mSharedLibraries = new ArrayMap<>();
102 
103     // These are the features this devices supports that were read from the
104     // system configuration files.
105     final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
106 
107     // These are the features which this device doesn't support; the OEM
108     // partition uses these to opt-out of features from the system image.
109     final ArraySet<String> mUnavailableFeatures = new ArraySet<>();
110 
111     public static final class PermissionEntry {
112         public final String name;
113         public int[] gids;
114         public boolean perUser;
115 
PermissionEntry(String name, boolean perUser)116         PermissionEntry(String name, boolean perUser) {
117             this.name = name;
118             this.perUser = perUser;
119         }
120     }
121 
122     // These are the permission -> gid mappings that were read from the
123     // system configuration files.
124     final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();
125 
126     // These are the packages that are white-listed to be able to run in the
127     // background while in power save mode (but not whitelisted from device idle modes),
128     // as read from the configuration files.
129     final ArraySet<String> mAllowInPowerSaveExceptIdle = new ArraySet<>();
130 
131     // These are the packages that are white-listed to be able to run in the
132     // background while in power save mode, as read from the configuration files.
133     final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
134 
135     // These are the packages that are white-listed to be able to run in the
136     // background while in data-usage save mode, as read from the configuration files.
137     final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>();
138 
139     // These are the packages that are white-listed to be able to run background location
140     // without throttling, as read from the configuration files.
141     final ArraySet<String> mAllowUnthrottledLocation = new ArraySet<>();
142 
143     // These are the packages that are white-listed to be able to retrieve location even when user
144     // location settings are off, for emergency purposes, as read from the configuration files.
145     final ArraySet<String> mAllowIgnoreLocationSettings = new ArraySet<>();
146 
147     // These are the action strings of broadcasts which are whitelisted to
148     // be delivered anonymously even to apps which target O+.
149     final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>();
150 
151     // These are the package names of apps which should be in the 'always'
152     // URL-handling state upon factory reset.
153     final ArraySet<String> mLinkedApps = new ArraySet<>();
154 
155     // These are the packages that are whitelisted to be able to run as system user
156     final ArraySet<String> mSystemUserWhitelistedApps = new ArraySet<>();
157 
158     // These are the packages that should not run under system user
159     final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();
160 
161     // These are the components that are enabled by default as VR mode listener services.
162     final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>();
163 
164     // These are the permitted backup transport service components
165     final ArraySet<ComponentName> mBackupTransportWhitelist = new ArraySet<>();
166 
167     // Package names that are exempted from private API blacklisting
168     final ArraySet<String> mHiddenApiPackageWhitelist = new ArraySet<>();
169 
170     // The list of carrier applications which should be disabled until used.
171     // This function suppresses update notifications for these pre-installed apps.
172     // In SubscriptionInfoUpdater, the listed applications are disabled until used when all of the
173     // following conditions are met.
174     // 1. Not currently carrier-privileged according to the inserted SIM
175     // 2. Pre-installed
176     // 3. In the default state (enabled but not explicitly)
177     // And SubscriptionInfoUpdater undoes this and marks the app enabled when a SIM is inserted
178     // that marks the app as carrier privileged. It also grants the app default permissions
179     // for Phone and Location. As such, apps MUST only ever be added to this list if they
180     // obtain user consent to access their location through other means.
181     final ArraySet<String> mDisabledUntilUsedPreinstalledCarrierApps = new ArraySet<>();
182 
183     // These are the packages of carrier-associated apps which should be disabled until used until
184     // a SIM is inserted which grants carrier privileges to that carrier app.
185     final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps =
186             new ArrayMap<>();
187 
188     final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>();
189     final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>();
190 
191     final ArrayMap<String, ArraySet<String>> mVendorPrivAppPermissions = new ArrayMap<>();
192     final ArrayMap<String, ArraySet<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>();
193 
194     final ArrayMap<String, ArraySet<String>> mProductPrivAppPermissions = new ArrayMap<>();
195     final ArrayMap<String, ArraySet<String>> mProductPrivAppDenyPermissions = new ArrayMap<>();
196 
197     final ArrayMap<String, ArraySet<String>> mProductServicesPrivAppPermissions = new ArrayMap<>();
198     final ArrayMap<String, ArraySet<String>> mProductServicesPrivAppDenyPermissions =
199             new ArrayMap<>();
200 
201     final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
202 
203     // Allowed associations between applications.  If there are any entries
204     // for an app, those are the only associations allowed; otherwise, all associations
205     // are allowed.  Allowing an association from app A to app B means app A can not
206     // associate with any other apps, but does not limit what apps B can associate with.
207     final ArrayMap<String, ArraySet<String>> mAllowedAssociations = new ArrayMap<>();
208 
209     private final ArraySet<String> mBugreportWhitelistedPackages = new ArraySet<>();
210 
getInstance()211     public static SystemConfig getInstance() {
212         synchronized (SystemConfig.class) {
213             if (sInstance == null) {
214                 sInstance = new SystemConfig();
215             }
216             return sInstance;
217         }
218     }
219 
getGlobalGids()220     public int[] getGlobalGids() {
221         return mGlobalGids;
222     }
223 
getSystemPermissions()224     public SparseArray<ArraySet<String>> getSystemPermissions() {
225         return mSystemPermissions;
226     }
227 
getSplitPermissions()228     public ArrayList<SplitPermissionInfo> getSplitPermissions() {
229         return mSplitPermissions;
230     }
231 
getSharedLibraries()232     public ArrayMap<String, SharedLibraryEntry> getSharedLibraries() {
233         return mSharedLibraries;
234     }
235 
getAvailableFeatures()236     public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
237         return mAvailableFeatures;
238     }
239 
getPermissions()240     public ArrayMap<String, PermissionEntry> getPermissions() {
241         return mPermissions;
242     }
243 
getAllowImplicitBroadcasts()244     public ArraySet<String> getAllowImplicitBroadcasts() {
245         return mAllowImplicitBroadcasts;
246     }
247 
getAllowInPowerSaveExceptIdle()248     public ArraySet<String> getAllowInPowerSaveExceptIdle() {
249         return mAllowInPowerSaveExceptIdle;
250     }
251 
getAllowInPowerSave()252     public ArraySet<String> getAllowInPowerSave() {
253         return mAllowInPowerSave;
254     }
255 
getAllowInDataUsageSave()256     public ArraySet<String> getAllowInDataUsageSave() {
257         return mAllowInDataUsageSave;
258     }
259 
getAllowUnthrottledLocation()260     public ArraySet<String> getAllowUnthrottledLocation() {
261         return mAllowUnthrottledLocation;
262     }
263 
getAllowIgnoreLocationSettings()264     public ArraySet<String> getAllowIgnoreLocationSettings() {
265         return mAllowIgnoreLocationSettings;
266     }
267 
getLinkedApps()268     public ArraySet<String> getLinkedApps() {
269         return mLinkedApps;
270     }
271 
getSystemUserWhitelistedApps()272     public ArraySet<String> getSystemUserWhitelistedApps() {
273         return mSystemUserWhitelistedApps;
274     }
275 
getSystemUserBlacklistedApps()276     public ArraySet<String> getSystemUserBlacklistedApps() {
277         return mSystemUserBlacklistedApps;
278     }
279 
getHiddenApiWhitelistedApps()280     public ArraySet<String> getHiddenApiWhitelistedApps() {
281         return mHiddenApiPackageWhitelist;
282     }
283 
getDefaultVrComponents()284     public ArraySet<ComponentName> getDefaultVrComponents() {
285         return mDefaultVrComponents;
286     }
287 
getBackupTransportWhitelist()288     public ArraySet<ComponentName> getBackupTransportWhitelist() {
289         return mBackupTransportWhitelist;
290     }
291 
getDisabledUntilUsedPreinstalledCarrierApps()292     public ArraySet<String> getDisabledUntilUsedPreinstalledCarrierApps() {
293         return mDisabledUntilUsedPreinstalledCarrierApps;
294     }
295 
getDisabledUntilUsedPreinstalledCarrierAssociatedApps()296     public ArrayMap<String, List<String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps() {
297         return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
298     }
299 
getPrivAppPermissions(String packageName)300     public ArraySet<String> getPrivAppPermissions(String packageName) {
301         return mPrivAppPermissions.get(packageName);
302     }
303 
getPrivAppDenyPermissions(String packageName)304     public ArraySet<String> getPrivAppDenyPermissions(String packageName) {
305         return mPrivAppDenyPermissions.get(packageName);
306     }
307 
getVendorPrivAppPermissions(String packageName)308     public ArraySet<String> getVendorPrivAppPermissions(String packageName) {
309         return mVendorPrivAppPermissions.get(packageName);
310     }
311 
getVendorPrivAppDenyPermissions(String packageName)312     public ArraySet<String> getVendorPrivAppDenyPermissions(String packageName) {
313         return mVendorPrivAppDenyPermissions.get(packageName);
314     }
315 
getProductPrivAppPermissions(String packageName)316     public ArraySet<String> getProductPrivAppPermissions(String packageName) {
317         return mProductPrivAppPermissions.get(packageName);
318     }
319 
getProductPrivAppDenyPermissions(String packageName)320     public ArraySet<String> getProductPrivAppDenyPermissions(String packageName) {
321         return mProductPrivAppDenyPermissions.get(packageName);
322     }
323 
getProductServicesPrivAppPermissions(String packageName)324     public ArraySet<String> getProductServicesPrivAppPermissions(String packageName) {
325         return mProductServicesPrivAppPermissions.get(packageName);
326     }
327 
getProductServicesPrivAppDenyPermissions(String packageName)328     public ArraySet<String> getProductServicesPrivAppDenyPermissions(String packageName) {
329         return mProductServicesPrivAppDenyPermissions.get(packageName);
330     }
331 
getOemPermissions(String packageName)332     public Map<String, Boolean> getOemPermissions(String packageName) {
333         final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName);
334         if (oemPermissions != null) {
335             return oemPermissions;
336         }
337         return Collections.emptyMap();
338     }
339 
getAllowedAssociations()340     public ArrayMap<String, ArraySet<String>> getAllowedAssociations() {
341         return mAllowedAssociations;
342     }
343 
getBugreportWhitelistedPackages()344     public ArraySet<String> getBugreportWhitelistedPackages() {
345         return mBugreportWhitelistedPackages;
346     }
347 
SystemConfig()348     SystemConfig() {
349         // Read configuration from system
350         readPermissions(Environment.buildPath(
351                 Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
352 
353         // Read configuration from the old permissions dir
354         readPermissions(Environment.buildPath(
355                 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
356 
357         // Vendors are only allowed to customize these
358         int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS
359                 | ALLOW_ASSOCIATIONS;
360         if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
361             // For backward compatibility
362             vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
363         }
364         readPermissions(Environment.buildPath(
365                 Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
366         readPermissions(Environment.buildPath(
367                 Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
368 
369         // Allow ODM to customize system configs as much as Vendor, because /odm is another
370         // vendor partition other than /vendor.
371         int odmPermissionFlag = vendorPermissionFlag;
372         readPermissions(Environment.buildPath(
373                 Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
374         readPermissions(Environment.buildPath(
375                 Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
376 
377         String skuProperty = SystemProperties.get(SKU_PROPERTY, "");
378         if (!skuProperty.isEmpty()) {
379             String skuDir = "sku_" + skuProperty;
380 
381             readPermissions(Environment.buildPath(
382                     Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag);
383             readPermissions(Environment.buildPath(
384                     Environment.getOdmDirectory(), "etc", "permissions", skuDir),
385                     odmPermissionFlag);
386         }
387 
388         // Allow OEM to customize these
389         int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS;
390         readPermissions(Environment.buildPath(
391                 Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
392         readPermissions(Environment.buildPath(
393                 Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
394 
395         // Allow Product to customize all system configs
396         readPermissions(Environment.buildPath(
397                 Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);
398         readPermissions(Environment.buildPath(
399                 Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);
400 
401         // Allow /product_services to customize all system configs
402         readPermissions(Environment.buildPath(
403                 Environment.getProductServicesDirectory(), "etc", "sysconfig"), ALLOW_ALL);
404         readPermissions(Environment.buildPath(
405                 Environment.getProductServicesDirectory(), "etc", "permissions"), ALLOW_ALL);
406     }
407 
readPermissions(File libraryDir, int permissionFlag)408     void readPermissions(File libraryDir, int permissionFlag) {
409         // Read permissions from given directory.
410         if (!libraryDir.exists() || !libraryDir.isDirectory()) {
411             if (permissionFlag == ALLOW_ALL) {
412                 Slog.w(TAG, "No directory " + libraryDir + ", skipping");
413             }
414             return;
415         }
416         if (!libraryDir.canRead()) {
417             Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
418             return;
419         }
420 
421         // Iterate over the files in the directory and scan .xml files
422         File platformFile = null;
423         for (File f : libraryDir.listFiles()) {
424             if (!f.isFile()) {
425                 continue;
426             }
427 
428             // We'll read platform.xml last
429             if (f.getPath().endsWith("etc/permissions/platform.xml")) {
430                 platformFile = f;
431                 continue;
432             }
433 
434             if (!f.getPath().endsWith(".xml")) {
435                 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
436                 continue;
437             }
438             if (!f.canRead()) {
439                 Slog.w(TAG, "Permissions library file " + f + " cannot be read");
440                 continue;
441             }
442 
443             readPermissionsFromXml(f, permissionFlag);
444         }
445 
446         // Read platform permissions last so it will take precedence
447         if (platformFile != null) {
448             readPermissionsFromXml(platformFile, permissionFlag);
449         }
450     }
451 
logNotAllowedInPartition(String name, File permFile, XmlPullParser parser)452     private void logNotAllowedInPartition(String name, File permFile, XmlPullParser parser) {
453         Slog.w(TAG, "<" + name + "> not allowed in partition of "
454                 + permFile + " at " + parser.getPositionDescription());
455     }
456 
readPermissionsFromXml(File permFile, int permissionFlag)457     private void readPermissionsFromXml(File permFile, int permissionFlag) {
458         FileReader permReader = null;
459         try {
460             permReader = new FileReader(permFile);
461         } catch (FileNotFoundException e) {
462             Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
463             return;
464         }
465 
466         final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
467 
468         try {
469             XmlPullParser parser = Xml.newPullParser();
470             parser.setInput(permReader);
471 
472             int type;
473             while ((type=parser.next()) != parser.START_TAG
474                        && type != parser.END_DOCUMENT) {
475                 ;
476             }
477 
478             if (type != parser.START_TAG) {
479                 throw new XmlPullParserException("No start tag found");
480             }
481 
482             if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
483                 throw new XmlPullParserException("Unexpected start tag in " + permFile
484                         + ": found " + parser.getName() + ", expected 'permissions' or 'config'");
485             }
486 
487             final boolean allowAll = permissionFlag == ALLOW_ALL;
488             final boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
489             final boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
490             final boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
491             final boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
492             final boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS)
493                     != 0;
494             final boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0;
495             final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING)
496                     != 0;
497             final boolean allowAssociations = (permissionFlag & ALLOW_ASSOCIATIONS) != 0;
498             while (true) {
499                 XmlUtils.nextElement(parser);
500                 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
501                     break;
502                 }
503 
504                 String name = parser.getName();
505                 if (name == null) {
506                     XmlUtils.skipCurrentTag(parser);
507                     continue;
508                 }
509                 switch (name) {
510                     case "group": {
511                         if (allowAll) {
512                             String gidStr = parser.getAttributeValue(null, "gid");
513                             if (gidStr != null) {
514                                 int gid = android.os.Process.getGidForName(gidStr);
515                                 mGlobalGids = appendInt(mGlobalGids, gid);
516                             } else {
517                                 Slog.w(TAG, "<" + name + "> without gid in " + permFile + " at "
518                                         + parser.getPositionDescription());
519                             }
520                         } else {
521                             logNotAllowedInPartition(name, permFile, parser);
522                         }
523                         XmlUtils.skipCurrentTag(parser);
524                     } break;
525                     case "permission": {
526                         if (allowPermissions) {
527                             String perm = parser.getAttributeValue(null, "name");
528                             if (perm == null) {
529                                 Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "
530                                         + parser.getPositionDescription());
531                                 XmlUtils.skipCurrentTag(parser);
532                                 break;
533                             }
534                             perm = perm.intern();
535                             readPermission(parser, perm);
536                         } else {
537                             logNotAllowedInPartition(name, permFile, parser);
538                             XmlUtils.skipCurrentTag(parser);
539                         }
540                     } break;
541                     case "assign-permission": {
542                         if (allowPermissions) {
543                             String perm = parser.getAttributeValue(null, "name");
544                             if (perm == null) {
545                                 Slog.w(TAG, "<" + name + "> without name in " + permFile
546                                         + " at " + parser.getPositionDescription());
547                                 XmlUtils.skipCurrentTag(parser);
548                                 break;
549                             }
550                             String uidStr = parser.getAttributeValue(null, "uid");
551                             if (uidStr == null) {
552                                 Slog.w(TAG, "<" + name + "> without uid in " + permFile
553                                         + " at " + parser.getPositionDescription());
554                                 XmlUtils.skipCurrentTag(parser);
555                                 break;
556                             }
557                             int uid = Process.getUidForName(uidStr);
558                             if (uid < 0) {
559                                 Slog.w(TAG, "<" + name + "> with unknown uid \""
560                                         + uidStr + "  in " + permFile + " at "
561                                         + parser.getPositionDescription());
562                                 XmlUtils.skipCurrentTag(parser);
563                                 break;
564                             }
565                             perm = perm.intern();
566                             ArraySet<String> perms = mSystemPermissions.get(uid);
567                             if (perms == null) {
568                                 perms = new ArraySet<String>();
569                                 mSystemPermissions.put(uid, perms);
570                             }
571                             perms.add(perm);
572                         } else {
573                             logNotAllowedInPartition(name, permFile, parser);
574                         }
575                         XmlUtils.skipCurrentTag(parser);
576                     } break;
577                     case "split-permission": {
578                         if (allowPermissions) {
579                             readSplitPermission(parser, permFile);
580                         } else {
581                             logNotAllowedInPartition(name, permFile, parser);
582                             XmlUtils.skipCurrentTag(parser);
583                         }
584                     } break;
585                     case "library": {
586                         if (allowLibs) {
587                             String lname = parser.getAttributeValue(null, "name");
588                             String lfile = parser.getAttributeValue(null, "file");
589                             String ldependency = parser.getAttributeValue(null, "dependency");
590                             if (lname == null) {
591                                 Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "
592                                         + parser.getPositionDescription());
593                             } else if (lfile == null) {
594                                 Slog.w(TAG, "<" + name + "> without file in " + permFile + " at "
595                                         + parser.getPositionDescription());
596                             } else {
597                                 //Log.i(TAG, "Got library " + lname + " in " + lfile);
598                                 SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile,
599                                         ldependency == null ? new String[0] : ldependency.split(":"));
600                                 mSharedLibraries.put(lname, entry);
601                             }
602                         } else {
603                             logNotAllowedInPartition(name, permFile, parser);
604                         }
605                         XmlUtils.skipCurrentTag(parser);
606                     } break;
607                     case "feature": {
608                         if (allowFeatures) {
609                             String fname = parser.getAttributeValue(null, "name");
610                             int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
611                             boolean allowed;
612                             if (!lowRam) {
613                                 allowed = true;
614                             } else {
615                                 String notLowRam = parser.getAttributeValue(null, "notLowRam");
616                                 allowed = !"true".equals(notLowRam);
617                             }
618                             if (fname == null) {
619                                 Slog.w(TAG, "<" + name + "> without name in " + permFile + " at "
620                                         + parser.getPositionDescription());
621                             } else if (allowed) {
622                                 addFeature(fname, fversion);
623                             }
624                         } else {
625                             logNotAllowedInPartition(name, permFile, parser);
626                         }
627                         XmlUtils.skipCurrentTag(parser);
628                     } break;
629                     case "unavailable-feature": {
630                         if (allowFeatures) {
631                             String fname = parser.getAttributeValue(null, "name");
632                             if (fname == null) {
633                                 Slog.w(TAG, "<" + name + "> without name in " + permFile
634                                         + " at " + parser.getPositionDescription());
635                             } else {
636                                 mUnavailableFeatures.add(fname);
637                             }
638                         } else {
639                             logNotAllowedInPartition(name, permFile, parser);
640                         }
641                         XmlUtils.skipCurrentTag(parser);
642                     } break;
643                     case "allow-in-power-save-except-idle": {
644                         if (allowAll) {
645                             String pkgname = parser.getAttributeValue(null, "package");
646                             if (pkgname == null) {
647                                 Slog.w(TAG, "<" + name + "> without package in "
648                                         + permFile + " at " + parser.getPositionDescription());
649                             } else {
650                                 mAllowInPowerSaveExceptIdle.add(pkgname);
651                             }
652                         } else {
653                             logNotAllowedInPartition(name, permFile, parser);
654                         }
655                         XmlUtils.skipCurrentTag(parser);
656                     } break;
657                     case "allow-in-power-save": {
658                         if (allowAll) {
659                             String pkgname = parser.getAttributeValue(null, "package");
660                             if (pkgname == null) {
661                                 Slog.w(TAG, "<" + name + "> without package in "
662                                         + permFile + " at " + parser.getPositionDescription());
663                             } else {
664                                 mAllowInPowerSave.add(pkgname);
665                             }
666                         } else {
667                             logNotAllowedInPartition(name, permFile, parser);
668                         }
669                         XmlUtils.skipCurrentTag(parser);
670                     } break;
671                     case "allow-in-data-usage-save": {
672                         if (allowAll) {
673                             String pkgname = parser.getAttributeValue(null, "package");
674                             if (pkgname == null) {
675                                 Slog.w(TAG, "<" + name + "> without package in "
676                                         + permFile + " at " + parser.getPositionDescription());
677                             } else {
678                                 mAllowInDataUsageSave.add(pkgname);
679                             }
680                         } else {
681                             logNotAllowedInPartition(name, permFile, parser);
682                         }
683                         XmlUtils.skipCurrentTag(parser);
684                     } break;
685                     case "allow-unthrottled-location": {
686                         if (allowAll) {
687                             String pkgname = parser.getAttributeValue(null, "package");
688                             if (pkgname == null) {
689                                 Slog.w(TAG, "<" + name + "> without package in "
690                                         + permFile + " at " + parser.getPositionDescription());
691                             } else {
692                                 mAllowUnthrottledLocation.add(pkgname);
693                             }
694                         } else {
695                             logNotAllowedInPartition(name, permFile, parser);
696                         }
697                         XmlUtils.skipCurrentTag(parser);
698                     } break;
699                     case "allow-ignore-location-settings": {
700                         if (allowAll) {
701                             String pkgname = parser.getAttributeValue(null, "package");
702                             if (pkgname == null) {
703                                 Slog.w(TAG, "<" + name + "> without package in "
704                                         + permFile + " at " + parser.getPositionDescription());
705                             } else {
706                                 mAllowIgnoreLocationSettings.add(pkgname);
707                             }
708                         } else {
709                             logNotAllowedInPartition(name, permFile, parser);
710                         }
711                         XmlUtils.skipCurrentTag(parser);
712                     } break;
713                     case "allow-implicit-broadcast": {
714                         if (allowAll) {
715                             String action = parser.getAttributeValue(null, "action");
716                             if (action == null) {
717                                 Slog.w(TAG, "<" + name + "> without action in "
718                                         + permFile + " at " + parser.getPositionDescription());
719                             } else {
720                                 mAllowImplicitBroadcasts.add(action);
721                             }
722                         } else {
723                             logNotAllowedInPartition(name, permFile, parser);
724                         }
725                         XmlUtils.skipCurrentTag(parser);
726                     } break;
727                     case "app-link": {
728                         if (allowAppConfigs) {
729                             String pkgname = parser.getAttributeValue(null, "package");
730                             if (pkgname == null) {
731                                 Slog.w(TAG, "<" + name + "> without package in " + permFile
732                                         + " at " + parser.getPositionDescription());
733                             } else {
734                                 mLinkedApps.add(pkgname);
735                             }
736                         } else {
737                             logNotAllowedInPartition(name, permFile, parser);
738                         }
739                         XmlUtils.skipCurrentTag(parser);
740                     } break;
741                     case "system-user-whitelisted-app": {
742                         if (allowAppConfigs) {
743                             String pkgname = parser.getAttributeValue(null, "package");
744                             if (pkgname == null) {
745                                 Slog.w(TAG, "<" + name + "> without package in "
746                                         + permFile + " at " + parser.getPositionDescription());
747                             } else {
748                                 mSystemUserWhitelistedApps.add(pkgname);
749                             }
750                         } else {
751                             logNotAllowedInPartition(name, permFile, parser);
752                         }
753                         XmlUtils.skipCurrentTag(parser);
754                     } break;
755                     case "system-user-blacklisted-app": {
756                         if (allowAppConfigs) {
757                             String pkgname = parser.getAttributeValue(null, "package");
758                             if (pkgname == null) {
759                                 Slog.w(TAG, "<" + name + "> without package in "
760                                         + permFile + " at " + parser.getPositionDescription());
761                             } else {
762                                 mSystemUserBlacklistedApps.add(pkgname);
763                             }
764                         } else {
765                             logNotAllowedInPartition(name, permFile, parser);
766                         }
767                         XmlUtils.skipCurrentTag(parser);
768                     } break;
769                     case "default-enabled-vr-app": {
770                         if (allowAppConfigs) {
771                             String pkgname = parser.getAttributeValue(null, "package");
772                             String clsname = parser.getAttributeValue(null, "class");
773                             if (pkgname == null) {
774                                 Slog.w(TAG, "<" + name + "> without package in "
775                                         + permFile + " at " + parser.getPositionDescription());
776                             } else if (clsname == null) {
777                                 Slog.w(TAG, "<" + name + "> without class in "
778                                         + permFile + " at " + parser.getPositionDescription());
779                             } else {
780                                 mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
781                             }
782                         } else {
783                             logNotAllowedInPartition(name, permFile, parser);
784                         }
785                         XmlUtils.skipCurrentTag(parser);
786                     } break;
787                     case "backup-transport-whitelisted-service": {
788                         if (allowFeatures) {
789                             String serviceName = parser.getAttributeValue(null, "service");
790                             if (serviceName == null) {
791                                 Slog.w(TAG, "<" + name + "> without service in "
792                                         + permFile + " at " + parser.getPositionDescription());
793                             } else {
794                                 ComponentName cn = ComponentName.unflattenFromString(serviceName);
795                                 if (cn == null) {
796                                     Slog.w(TAG, "<" + name + "> with invalid service name "
797                                             + serviceName + " in " + permFile
798                                             + " at " + parser.getPositionDescription());
799                                 } else {
800                                     mBackupTransportWhitelist.add(cn);
801                                 }
802                             }
803                         } else {
804                             logNotAllowedInPartition(name, permFile, parser);
805                         }
806                         XmlUtils.skipCurrentTag(parser);
807                     } break;
808                     case "disabled-until-used-preinstalled-carrier-associated-app": {
809                         if (allowAppConfigs) {
810                             String pkgname = parser.getAttributeValue(null, "package");
811                             String carrierPkgname = parser.getAttributeValue(null,
812                                     "carrierAppPackage");
813                             if (pkgname == null || carrierPkgname == null) {
814                                 Slog.w(TAG, "<" + name
815                                         + "> without package or carrierAppPackage in " + permFile
816                                         + " at " + parser.getPositionDescription());
817                             } else {
818                                 List<String> associatedPkgs =
819                                         mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(
820                                                 carrierPkgname);
821                                 if (associatedPkgs == null) {
822                                     associatedPkgs = new ArrayList<>();
823                                     mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(
824                                             carrierPkgname, associatedPkgs);
825                                 }
826                                 associatedPkgs.add(pkgname);
827                             }
828                         } else {
829                             logNotAllowedInPartition(name, permFile, parser);
830                         }
831                         XmlUtils.skipCurrentTag(parser);
832                     } break;
833                     case "disabled-until-used-preinstalled-carrier-app": {
834                         if (allowAppConfigs) {
835                             String pkgname = parser.getAttributeValue(null, "package");
836                             if (pkgname == null) {
837                                 Slog.w(TAG,
838                                         "<" + name + "> without "
839                                                 + "package in " + permFile + " at "
840                                                 + parser.getPositionDescription());
841                             } else {
842                                 mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname);
843                             }
844                         } else {
845                             logNotAllowedInPartition(name, permFile, parser);
846                         }
847                         XmlUtils.skipCurrentTag(parser);
848                     } break;
849                     case "privapp-permissions": {
850                         if (allowPrivappPermissions) {
851                             // privapp permissions from system, vendor, product and product_services
852                             // partitions are stored separately. This is to prevent xml files in
853                             // the vendor partition from granting permissions to priv apps in the
854                             // system partition and vice versa.
855                             boolean vendor = permFile.toPath().startsWith(
856                                     Environment.getVendorDirectory().toPath() + "/")
857                                     || permFile.toPath().startsWith(
858                                     Environment.getOdmDirectory().toPath() + "/");
859                             boolean product = permFile.toPath().startsWith(
860                                     Environment.getProductDirectory().toPath() + "/");
861                             boolean productServices = permFile.toPath().startsWith(
862                                     Environment.getProductServicesDirectory().toPath() + "/");
863                             if (vendor) {
864                                 readPrivAppPermissions(parser, mVendorPrivAppPermissions,
865                                         mVendorPrivAppDenyPermissions);
866                             } else if (product) {
867                                 readPrivAppPermissions(parser, mProductPrivAppPermissions,
868                                         mProductPrivAppDenyPermissions);
869                             } else if (productServices) {
870                                 readPrivAppPermissions(parser, mProductServicesPrivAppPermissions,
871                                         mProductServicesPrivAppDenyPermissions);
872                             } else {
873                                 readPrivAppPermissions(parser, mPrivAppPermissions,
874                                         mPrivAppDenyPermissions);
875                             }
876                         } else {
877                             logNotAllowedInPartition(name, permFile, parser);
878                             XmlUtils.skipCurrentTag(parser);
879                         }
880                     } break;
881                     case "oem-permissions": {
882                         if (allowOemPermissions) {
883                             readOemPermissions(parser);
884                         } else {
885                             logNotAllowedInPartition(name, permFile, parser);
886                             XmlUtils.skipCurrentTag(parser);
887                         }
888                     } break;
889                     case "hidden-api-whitelisted-app": {
890                         if (allowApiWhitelisting) {
891                             String pkgname = parser.getAttributeValue(null, "package");
892                             if (pkgname == null) {
893                                 Slog.w(TAG, "<" + name + "> without package in "
894                                         + permFile + " at " + parser.getPositionDescription());
895                             } else {
896                                 mHiddenApiPackageWhitelist.add(pkgname);
897                             }
898                         } else {
899                             logNotAllowedInPartition(name, permFile, parser);
900                         }
901                         XmlUtils.skipCurrentTag(parser);
902                     } break;
903                     case "allow-association": {
904                         if (allowAssociations) {
905                             String target = parser.getAttributeValue(null, "target");
906                             if (target == null) {
907                                 Slog.w(TAG, "<" + name + "> without target in " + permFile
908                                         + " at " + parser.getPositionDescription());
909                                 XmlUtils.skipCurrentTag(parser);
910                                 break;
911                             }
912                             String allowed = parser.getAttributeValue(null, "allowed");
913                             if (allowed == null) {
914                                 Slog.w(TAG, "<" + name + "> without allowed in " + permFile
915                                         + " at " + parser.getPositionDescription());
916                                 XmlUtils.skipCurrentTag(parser);
917                                 break;
918                             }
919                             target = target.intern();
920                             allowed = allowed.intern();
921                             ArraySet<String> associations = mAllowedAssociations.get(target);
922                             if (associations == null) {
923                                 associations = new ArraySet<>();
924                                 mAllowedAssociations.put(target, associations);
925                             }
926                             Slog.i(TAG, "Adding association: " + target + " <- " + allowed);
927                             associations.add(allowed);
928                         } else {
929                             logNotAllowedInPartition(name, permFile, parser);
930                         }
931                         XmlUtils.skipCurrentTag(parser);
932                     } break;
933                     case "bugreport-whitelisted": {
934                         String pkgname = parser.getAttributeValue(null, "package");
935                         if (pkgname == null) {
936                             Slog.w(TAG, "<" + name + "> without package in " + permFile
937                                     + " at " + parser.getPositionDescription());
938                         } else {
939                             mBugreportWhitelistedPackages.add(pkgname);
940                         }
941                         XmlUtils.skipCurrentTag(parser);
942                     } break;
943                     default: {
944                         Slog.w(TAG, "Tag " + name + " is unknown in "
945                                 + permFile + " at " + parser.getPositionDescription());
946                         XmlUtils.skipCurrentTag(parser);
947                     } break;
948                 }
949             }
950         } catch (XmlPullParserException e) {
951             Slog.w(TAG, "Got exception parsing permissions.", e);
952         } catch (IOException e) {
953             Slog.w(TAG, "Got exception parsing permissions.", e);
954         } finally {
955             IoUtils.closeQuietly(permReader);
956         }
957 
958         // Some devices can be field-converted to FBE, so offer to splice in
959         // those features if not already defined by the static config
960         if (StorageManager.isFileEncryptedNativeOnly()) {
961             addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
962             addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
963         }
964 
965         // Help legacy devices that may not have updated their static config
966         if (StorageManager.hasAdoptable()) {
967             addFeature(PackageManager.FEATURE_ADOPTABLE_STORAGE, 0);
968         }
969 
970         if (ActivityManager.isLowRamDeviceStatic()) {
971             addFeature(PackageManager.FEATURE_RAM_LOW, 0);
972         } else {
973             addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);
974         }
975 
976         for (String featureName : mUnavailableFeatures) {
977             removeFeature(featureName);
978         }
979     }
980 
addFeature(String name, int version)981     private void addFeature(String name, int version) {
982         FeatureInfo fi = mAvailableFeatures.get(name);
983         if (fi == null) {
984             fi = new FeatureInfo();
985             fi.name = name;
986             fi.version = version;
987             mAvailableFeatures.put(name, fi);
988         } else {
989             fi.version = Math.max(fi.version, version);
990         }
991     }
992 
removeFeature(String name)993     private void removeFeature(String name) {
994         if (mAvailableFeatures.remove(name) != null) {
995             Slog.d(TAG, "Removed unavailable feature " + name);
996         }
997     }
998 
readPermission(XmlPullParser parser, String name)999     void readPermission(XmlPullParser parser, String name)
1000             throws IOException, XmlPullParserException {
1001         if (mPermissions.containsKey(name)) {
1002             throw new IllegalStateException("Duplicate permission definition for " + name);
1003         }
1004 
1005         final boolean perUser = XmlUtils.readBooleanAttribute(parser, "perUser", false);
1006         final PermissionEntry perm = new PermissionEntry(name, perUser);
1007         mPermissions.put(name, perm);
1008 
1009         int outerDepth = parser.getDepth();
1010         int type;
1011         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1012                && (type != XmlPullParser.END_TAG
1013                        || parser.getDepth() > outerDepth)) {
1014             if (type == XmlPullParser.END_TAG
1015                     || type == XmlPullParser.TEXT) {
1016                 continue;
1017             }
1018 
1019             String tagName = parser.getName();
1020             if ("group".equals(tagName)) {
1021                 String gidStr = parser.getAttributeValue(null, "gid");
1022                 if (gidStr != null) {
1023                     int gid = Process.getGidForName(gidStr);
1024                     perm.gids = appendInt(perm.gids, gid);
1025                 } else {
1026                     Slog.w(TAG, "<group> without gid at "
1027                             + parser.getPositionDescription());
1028                 }
1029             }
1030             XmlUtils.skipCurrentTag(parser);
1031         }
1032     }
1033 
readPrivAppPermissions(XmlPullParser parser, ArrayMap<String, ArraySet<String>> grantMap, ArrayMap<String, ArraySet<String>> denyMap)1034     private void readPrivAppPermissions(XmlPullParser parser,
1035             ArrayMap<String, ArraySet<String>> grantMap,
1036             ArrayMap<String, ArraySet<String>> denyMap)
1037             throws IOException, XmlPullParserException {
1038         String packageName = parser.getAttributeValue(null, "package");
1039         if (TextUtils.isEmpty(packageName)) {
1040             Slog.w(TAG, "package is required for <privapp-permissions> in "
1041                     + parser.getPositionDescription());
1042             return;
1043         }
1044 
1045         ArraySet<String> permissions = grantMap.get(packageName);
1046         if (permissions == null) {
1047             permissions = new ArraySet<>();
1048         }
1049         ArraySet<String> denyPermissions = denyMap.get(packageName);
1050         int depth = parser.getDepth();
1051         while (XmlUtils.nextElementWithin(parser, depth)) {
1052             String name = parser.getName();
1053             if ("permission".equals(name)) {
1054                 String permName = parser.getAttributeValue(null, "name");
1055                 if (TextUtils.isEmpty(permName)) {
1056                     Slog.w(TAG, "name is required for <permission> in "
1057                             + parser.getPositionDescription());
1058                     continue;
1059                 }
1060                 permissions.add(permName);
1061             } else if ("deny-permission".equals(name)) {
1062                 String permName = parser.getAttributeValue(null, "name");
1063                 if (TextUtils.isEmpty(permName)) {
1064                     Slog.w(TAG, "name is required for <deny-permission> in "
1065                             + parser.getPositionDescription());
1066                     continue;
1067                 }
1068                 if (denyPermissions == null) {
1069                     denyPermissions = new ArraySet<>();
1070                 }
1071                 denyPermissions.add(permName);
1072             }
1073         }
1074         grantMap.put(packageName, permissions);
1075         if (denyPermissions != null) {
1076             denyMap.put(packageName, denyPermissions);
1077         }
1078     }
1079 
readOemPermissions(XmlPullParser parser)1080     void readOemPermissions(XmlPullParser parser) throws IOException, XmlPullParserException {
1081         final String packageName = parser.getAttributeValue(null, "package");
1082         if (TextUtils.isEmpty(packageName)) {
1083             Slog.w(TAG, "package is required for <oem-permissions> in "
1084                     + parser.getPositionDescription());
1085             return;
1086         }
1087 
1088         ArrayMap<String, Boolean> permissions = mOemPermissions.get(packageName);
1089         if (permissions == null) {
1090             permissions = new ArrayMap<>();
1091         }
1092         final int depth = parser.getDepth();
1093         while (XmlUtils.nextElementWithin(parser, depth)) {
1094             final String name = parser.getName();
1095             if ("permission".equals(name)) {
1096                 final String permName = parser.getAttributeValue(null, "name");
1097                 if (TextUtils.isEmpty(permName)) {
1098                     Slog.w(TAG, "name is required for <permission> in "
1099                             + parser.getPositionDescription());
1100                     continue;
1101                 }
1102                 permissions.put(permName, Boolean.TRUE);
1103             } else if ("deny-permission".equals(name)) {
1104                 String permName = parser.getAttributeValue(null, "name");
1105                 if (TextUtils.isEmpty(permName)) {
1106                     Slog.w(TAG, "name is required for <deny-permission> in "
1107                             + parser.getPositionDescription());
1108                     continue;
1109                 }
1110                 permissions.put(permName, Boolean.FALSE);
1111             }
1112         }
1113         mOemPermissions.put(packageName, permissions);
1114     }
1115 
readSplitPermission(XmlPullParser parser, File permFile)1116     private void readSplitPermission(XmlPullParser parser, File permFile)
1117             throws IOException, XmlPullParserException {
1118         String splitPerm = parser.getAttributeValue(null, "name");
1119         if (splitPerm == null) {
1120             Slog.w(TAG, "<split-permission> without name in " + permFile + " at "
1121                     + parser.getPositionDescription());
1122             XmlUtils.skipCurrentTag(parser);
1123             return;
1124         }
1125         String targetSdkStr = parser.getAttributeValue(null, "targetSdk");
1126         int targetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT + 1;
1127         if (!TextUtils.isEmpty(targetSdkStr)) {
1128             try {
1129                 targetSdk = Integer.parseInt(targetSdkStr);
1130             } catch (NumberFormatException e) {
1131                 Slog.w(TAG, "<split-permission> targetSdk not an integer in " + permFile + " at "
1132                         + parser.getPositionDescription());
1133                 XmlUtils.skipCurrentTag(parser);
1134                 return;
1135             }
1136         }
1137         final int depth = parser.getDepth();
1138         List<String> newPermissions = new ArrayList<>();
1139         while (XmlUtils.nextElementWithin(parser, depth)) {
1140             String name = parser.getName();
1141             if ("new-permission".equals(name)) {
1142                 final String newName = parser.getAttributeValue(null, "name");
1143                 if (TextUtils.isEmpty(newName)) {
1144                     Slog.w(TAG, "name is required for <new-permission> in "
1145                             + parser.getPositionDescription());
1146                     continue;
1147                 }
1148                 newPermissions.add(newName);
1149             } else {
1150                 XmlUtils.skipCurrentTag(parser);
1151             }
1152         }
1153         if (!newPermissions.isEmpty()) {
1154             mSplitPermissions.add(new SplitPermissionInfo(splitPerm, newPermissions, targetSdk));
1155         }
1156     }
1157 }
1158