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.storage.StorageManager;
29 import android.text.TextUtils;
30 import android.util.ArrayMap;
31 import android.util.ArraySet;
32 import android.util.Slog;
33 import android.util.SparseArray;
34 import android.util.Xml;
35 
36 import com.android.internal.util.XmlUtils;
37 
38 import libcore.io.IoUtils;
39 
40 import org.xmlpull.v1.XmlPullParser;
41 import org.xmlpull.v1.XmlPullParserException;
42 
43 import java.io.File;
44 import java.io.FileNotFoundException;
45 import java.io.FileReader;
46 import java.io.IOException;
47 import java.util.ArrayList;
48 import java.util.Collections;
49 import java.util.List;
50 import java.util.Map;
51 
52 /**
53  * Loads global system configuration info.
54  */
55 public class SystemConfig {
56     static final String TAG = "SystemConfig";
57 
58     static SystemConfig sInstance;
59 
60     // permission flag, determines which types of configuration are allowed to be read
61     private static final int ALLOW_FEATURES = 0x01;
62     private static final int ALLOW_LIBS = 0x02;
63     private static final int ALLOW_PERMISSIONS = 0x04;
64     private static final int ALLOW_APP_CONFIGS = 0x08;
65     private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10;
66     private static final int ALLOW_OEM_PERMISSIONS = 0x20;
67     private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x40;
68     private static final int ALLOW_ALL = ~0;
69 
70     // Group-ids that are given to all packages as read from etc/permissions/*.xml.
71     int[] mGlobalGids;
72 
73     // These are the built-in uid -> permission mappings that were read from the
74     // system configuration files.
75     final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
76 
77     // These are the built-in shared libraries that were read from the
78     // system configuration files.  Keys are the library names; strings are the
79     // paths to the libraries.
80     final ArrayMap<String, String> mSharedLibraries  = new ArrayMap<>();
81 
82     // These are the features this devices supports that were read from the
83     // system configuration files.
84     final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
85 
86     // These are the features which this device doesn't support; the OEM
87     // partition uses these to opt-out of features from the system image.
88     final ArraySet<String> mUnavailableFeatures = new ArraySet<>();
89 
90     public static final class PermissionEntry {
91         public final String name;
92         public int[] gids;
93         public boolean perUser;
94 
PermissionEntry(String name, boolean perUser)95         PermissionEntry(String name, boolean perUser) {
96             this.name = name;
97             this.perUser = perUser;
98         }
99     }
100 
101     // These are the permission -> gid mappings that were read from the
102     // system configuration files.
103     final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();
104 
105     // These are the packages that are white-listed to be able to run in the
106     // background while in power save mode (but not whitelisted from device idle modes),
107     // as read from the configuration files.
108     final ArraySet<String> mAllowInPowerSaveExceptIdle = new ArraySet<>();
109 
110     // These are the packages that are white-listed to be able to run in the
111     // background while in power save mode, as read from the configuration files.
112     final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
113 
114     // These are the packages that are white-listed to be able to run in the
115     // background while in data-usage save mode, as read from the configuration files.
116     final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>();
117 
118     // These are the packages that are white-listed to be able to run background location
119     // without throttling, as read from the configuration files.
120     final ArraySet<String> mAllowUnthrottledLocation = new ArraySet<>();
121 
122     // These are the action strings of broadcasts which are whitelisted to
123     // be delivered anonymously even to apps which target O+.
124     final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>();
125 
126     // These are the package names of apps which should be in the 'always'
127     // URL-handling state upon factory reset.
128     final ArraySet<String> mLinkedApps = new ArraySet<>();
129 
130     // These are the packages that are whitelisted to be able to run as system user
131     final ArraySet<String> mSystemUserWhitelistedApps = new ArraySet<>();
132 
133     // These are the packages that should not run under system user
134     final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();
135 
136     // These are the components that are enabled by default as VR mode listener services.
137     final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>();
138 
139     // These are the permitted backup transport service components
140     final ArraySet<ComponentName> mBackupTransportWhitelist = new ArraySet<>();
141 
142     // Package names that are exempted from private API blacklisting
143     final ArraySet<String> mHiddenApiPackageWhitelist = new ArraySet<>();
144 
145     // The list of carrier applications which should be disabled until used.
146     // This function suppresses update notifications for these pre-installed apps.
147     // In SubscriptionInfoUpdater, the listed applications are disabled until used when all of the
148     // following conditions are met.
149     // 1. Not currently carrier-privileged according to the inserted SIM
150     // 2. Pre-installed
151     // 3. In the default state (enabled but not explicitly)
152     // And SubscriptionInfoUpdater undoes this and marks the app enabled when a SIM is inserted
153     // that marks the app as carrier privileged. It also grants the app default permissions
154     // for Phone and Location. As such, apps MUST only ever be added to this list if they
155     // obtain user consent to access their location through other means.
156     final ArraySet<String> mDisabledUntilUsedPreinstalledCarrierApps = new ArraySet<>();
157 
158     // These are the packages of carrier-associated apps which should be disabled until used until
159     // a SIM is inserted which grants carrier privileges to that carrier app.
160     final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps =
161             new ArrayMap<>();
162 
163     final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>();
164     final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>();
165 
166     final ArrayMap<String, ArraySet<String>> mVendorPrivAppPermissions = new ArrayMap<>();
167     final ArrayMap<String, ArraySet<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>();
168 
169     final ArrayMap<String, ArraySet<String>> mProductPrivAppPermissions = new ArrayMap<>();
170     final ArrayMap<String, ArraySet<String>> mProductPrivAppDenyPermissions = new ArrayMap<>();
171 
172     final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
173 
getInstance()174     public static SystemConfig getInstance() {
175         synchronized (SystemConfig.class) {
176             if (sInstance == null) {
177                 sInstance = new SystemConfig();
178             }
179             return sInstance;
180         }
181     }
182 
getGlobalGids()183     public int[] getGlobalGids() {
184         return mGlobalGids;
185     }
186 
getSystemPermissions()187     public SparseArray<ArraySet<String>> getSystemPermissions() {
188         return mSystemPermissions;
189     }
190 
getSharedLibraries()191     public ArrayMap<String, String> getSharedLibraries() {
192         return mSharedLibraries;
193     }
194 
getAvailableFeatures()195     public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
196         return mAvailableFeatures;
197     }
198 
getPermissions()199     public ArrayMap<String, PermissionEntry> getPermissions() {
200         return mPermissions;
201     }
202 
getAllowImplicitBroadcasts()203     public ArraySet<String> getAllowImplicitBroadcasts() {
204         return mAllowImplicitBroadcasts;
205     }
206 
getAllowInPowerSaveExceptIdle()207     public ArraySet<String> getAllowInPowerSaveExceptIdle() {
208         return mAllowInPowerSaveExceptIdle;
209     }
210 
getAllowInPowerSave()211     public ArraySet<String> getAllowInPowerSave() {
212         return mAllowInPowerSave;
213     }
214 
getAllowInDataUsageSave()215     public ArraySet<String> getAllowInDataUsageSave() {
216         return mAllowInDataUsageSave;
217     }
218 
getAllowUnthrottledLocation()219     public ArraySet<String> getAllowUnthrottledLocation() {
220         return mAllowUnthrottledLocation;
221     }
222 
getLinkedApps()223     public ArraySet<String> getLinkedApps() {
224         return mLinkedApps;
225     }
226 
getSystemUserWhitelistedApps()227     public ArraySet<String> getSystemUserWhitelistedApps() {
228         return mSystemUserWhitelistedApps;
229     }
230 
getSystemUserBlacklistedApps()231     public ArraySet<String> getSystemUserBlacklistedApps() {
232         return mSystemUserBlacklistedApps;
233     }
234 
getHiddenApiWhitelistedApps()235     public ArraySet<String> getHiddenApiWhitelistedApps() {
236         return mHiddenApiPackageWhitelist;
237     }
238 
getDefaultVrComponents()239     public ArraySet<ComponentName> getDefaultVrComponents() {
240         return mDefaultVrComponents;
241     }
242 
getBackupTransportWhitelist()243     public ArraySet<ComponentName> getBackupTransportWhitelist() {
244         return mBackupTransportWhitelist;
245     }
246 
getDisabledUntilUsedPreinstalledCarrierApps()247     public ArraySet<String> getDisabledUntilUsedPreinstalledCarrierApps() {
248         return mDisabledUntilUsedPreinstalledCarrierApps;
249     }
250 
getDisabledUntilUsedPreinstalledCarrierAssociatedApps()251     public ArrayMap<String, List<String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps() {
252         return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
253     }
254 
getPrivAppPermissions(String packageName)255     public ArraySet<String> getPrivAppPermissions(String packageName) {
256         return mPrivAppPermissions.get(packageName);
257     }
258 
getPrivAppDenyPermissions(String packageName)259     public ArraySet<String> getPrivAppDenyPermissions(String packageName) {
260         return mPrivAppDenyPermissions.get(packageName);
261     }
262 
getVendorPrivAppPermissions(String packageName)263     public ArraySet<String> getVendorPrivAppPermissions(String packageName) {
264         return mVendorPrivAppPermissions.get(packageName);
265     }
266 
getVendorPrivAppDenyPermissions(String packageName)267     public ArraySet<String> getVendorPrivAppDenyPermissions(String packageName) {
268         return mVendorPrivAppDenyPermissions.get(packageName);
269     }
270 
getProductPrivAppPermissions(String packageName)271     public ArraySet<String> getProductPrivAppPermissions(String packageName) {
272         return mProductPrivAppPermissions.get(packageName);
273     }
274 
getProductPrivAppDenyPermissions(String packageName)275     public ArraySet<String> getProductPrivAppDenyPermissions(String packageName) {
276         return mProductPrivAppDenyPermissions.get(packageName);
277     }
278 
getOemPermissions(String packageName)279     public Map<String, Boolean> getOemPermissions(String packageName) {
280         final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName);
281         if (oemPermissions != null) {
282             return oemPermissions;
283         }
284         return Collections.emptyMap();
285     }
286 
SystemConfig()287     SystemConfig() {
288         // Read configuration from system
289         readPermissions(Environment.buildPath(
290                 Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
291 
292         // Read configuration from the old permissions dir
293         readPermissions(Environment.buildPath(
294                 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
295 
296         // Vendors are only allowed to customze libs, features and privapp permissions
297         int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS;
298         if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
299             // For backward compatibility
300             vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
301         }
302         readPermissions(Environment.buildPath(
303                 Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
304         readPermissions(Environment.buildPath(
305                 Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
306 
307         // Allow ODM to customize system configs as much as Vendor, because /odm is another
308         // vendor partition other than /vendor.
309         int odmPermissionFlag = vendorPermissionFlag;
310         readPermissions(Environment.buildPath(
311                 Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
312         readPermissions(Environment.buildPath(
313                 Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
314 
315         // Allow OEM to customize features and OEM permissions
316         int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS;
317         readPermissions(Environment.buildPath(
318                 Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
319         readPermissions(Environment.buildPath(
320                 Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
321 
322         // Allow Product to customize system configs around libs, features, permissions and apps
323         int productPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
324                 ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
325         readPermissions(Environment.buildPath(
326                 Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag);
327         readPermissions(Environment.buildPath(
328                 Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag);
329     }
330 
readPermissions(File libraryDir, int permissionFlag)331     void readPermissions(File libraryDir, int permissionFlag) {
332         // Read permissions from given directory.
333         if (!libraryDir.exists() || !libraryDir.isDirectory()) {
334             if (permissionFlag == ALLOW_ALL) {
335                 Slog.w(TAG, "No directory " + libraryDir + ", skipping");
336             }
337             return;
338         }
339         if (!libraryDir.canRead()) {
340             Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
341             return;
342         }
343 
344         // Iterate over the files in the directory and scan .xml files
345         File platformFile = null;
346         for (File f : libraryDir.listFiles()) {
347             // We'll read platform.xml last
348             if (f.getPath().endsWith("etc/permissions/platform.xml")) {
349                 platformFile = f;
350                 continue;
351             }
352 
353             if (!f.getPath().endsWith(".xml")) {
354                 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
355                 continue;
356             }
357             if (!f.canRead()) {
358                 Slog.w(TAG, "Permissions library file " + f + " cannot be read");
359                 continue;
360             }
361 
362             readPermissionsFromXml(f, permissionFlag);
363         }
364 
365         // Read platform permissions last so it will take precedence
366         if (platformFile != null) {
367             readPermissionsFromXml(platformFile, permissionFlag);
368         }
369     }
370 
readPermissionsFromXml(File permFile, int permissionFlag)371     private void readPermissionsFromXml(File permFile, int permissionFlag) {
372         FileReader permReader = null;
373         try {
374             permReader = new FileReader(permFile);
375         } catch (FileNotFoundException e) {
376             Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
377             return;
378         }
379 
380         final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
381 
382         try {
383             XmlPullParser parser = Xml.newPullParser();
384             parser.setInput(permReader);
385 
386             int type;
387             while ((type=parser.next()) != parser.START_TAG
388                        && type != parser.END_DOCUMENT) {
389                 ;
390             }
391 
392             if (type != parser.START_TAG) {
393                 throw new XmlPullParserException("No start tag found");
394             }
395 
396             if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
397                 throw new XmlPullParserException("Unexpected start tag in " + permFile
398                         + ": found " + parser.getName() + ", expected 'permissions' or 'config'");
399             }
400 
401             boolean allowAll = permissionFlag == ALLOW_ALL;
402             boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
403             boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
404             boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
405             boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
406             boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0;
407             boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0;
408             boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) != 0;
409             while (true) {
410                 XmlUtils.nextElement(parser);
411                 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
412                     break;
413                 }
414 
415                 String name = parser.getName();
416                 if ("group".equals(name) && allowAll) {
417                     String gidStr = parser.getAttributeValue(null, "gid");
418                     if (gidStr != null) {
419                         int gid = android.os.Process.getGidForName(gidStr);
420                         mGlobalGids = appendInt(mGlobalGids, gid);
421                     } else {
422                         Slog.w(TAG, "<group> without gid in " + permFile + " at "
423                                 + parser.getPositionDescription());
424                     }
425 
426                     XmlUtils.skipCurrentTag(parser);
427                     continue;
428                 } else if ("permission".equals(name) && allowPermissions) {
429                     String perm = parser.getAttributeValue(null, "name");
430                     if (perm == null) {
431                         Slog.w(TAG, "<permission> without name in " + permFile + " at "
432                                 + parser.getPositionDescription());
433                         XmlUtils.skipCurrentTag(parser);
434                         continue;
435                     }
436                     perm = perm.intern();
437                     readPermission(parser, perm);
438 
439                 } else if ("assign-permission".equals(name) && allowPermissions) {
440                     String perm = parser.getAttributeValue(null, "name");
441                     if (perm == null) {
442                         Slog.w(TAG, "<assign-permission> without name in " + permFile + " at "
443                                 + parser.getPositionDescription());
444                         XmlUtils.skipCurrentTag(parser);
445                         continue;
446                     }
447                     String uidStr = parser.getAttributeValue(null, "uid");
448                     if (uidStr == null) {
449                         Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at "
450                                 + parser.getPositionDescription());
451                         XmlUtils.skipCurrentTag(parser);
452                         continue;
453                     }
454                     int uid = Process.getUidForName(uidStr);
455                     if (uid < 0) {
456                         Slog.w(TAG, "<assign-permission> with unknown uid \""
457                                 + uidStr + "  in " + permFile + " at "
458                                 + parser.getPositionDescription());
459                         XmlUtils.skipCurrentTag(parser);
460                         continue;
461                     }
462                     perm = perm.intern();
463                     ArraySet<String> perms = mSystemPermissions.get(uid);
464                     if (perms == null) {
465                         perms = new ArraySet<String>();
466                         mSystemPermissions.put(uid, perms);
467                     }
468                     perms.add(perm);
469                     XmlUtils.skipCurrentTag(parser);
470 
471                 } else if ("library".equals(name) && allowLibs) {
472                     String lname = parser.getAttributeValue(null, "name");
473                     String lfile = parser.getAttributeValue(null, "file");
474                     if (lname == null) {
475                         Slog.w(TAG, "<library> without name in " + permFile + " at "
476                                 + parser.getPositionDescription());
477                     } else if (lfile == null) {
478                         Slog.w(TAG, "<library> without file in " + permFile + " at "
479                                 + parser.getPositionDescription());
480                     } else {
481                         //Log.i(TAG, "Got library " + lname + " in " + lfile);
482                         mSharedLibraries.put(lname, lfile);
483                     }
484                     XmlUtils.skipCurrentTag(parser);
485                     continue;
486 
487                 } else if ("feature".equals(name) && allowFeatures) {
488                     String fname = parser.getAttributeValue(null, "name");
489                     int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
490                     boolean allowed;
491                     if (!lowRam) {
492                         allowed = true;
493                     } else {
494                         String notLowRam = parser.getAttributeValue(null, "notLowRam");
495                         allowed = !"true".equals(notLowRam);
496                     }
497                     if (fname == null) {
498                         Slog.w(TAG, "<feature> without name in " + permFile + " at "
499                                 + parser.getPositionDescription());
500                     } else if (allowed) {
501                         addFeature(fname, fversion);
502                     }
503                     XmlUtils.skipCurrentTag(parser);
504                     continue;
505 
506                 } else if ("unavailable-feature".equals(name) && allowFeatures) {
507                     String fname = parser.getAttributeValue(null, "name");
508                     if (fname == null) {
509                         Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
510                                 + parser.getPositionDescription());
511                     } else {
512                         mUnavailableFeatures.add(fname);
513                     }
514                     XmlUtils.skipCurrentTag(parser);
515                     continue;
516 
517                 } else if ("allow-in-power-save-except-idle".equals(name) && allowAll) {
518                     String pkgname = parser.getAttributeValue(null, "package");
519                     if (pkgname == null) {
520                         Slog.w(TAG, "<allow-in-power-save-except-idle> without package in "
521                                 + permFile + " at " + parser.getPositionDescription());
522                     } else {
523                         mAllowInPowerSaveExceptIdle.add(pkgname);
524                     }
525                     XmlUtils.skipCurrentTag(parser);
526                     continue;
527 
528                 } else if ("allow-in-power-save".equals(name) && allowAll) {
529                     String pkgname = parser.getAttributeValue(null, "package");
530                     if (pkgname == null) {
531                         Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
532                                 + parser.getPositionDescription());
533                     } else {
534                         mAllowInPowerSave.add(pkgname);
535                     }
536                     XmlUtils.skipCurrentTag(parser);
537                     continue;
538 
539                 } else if ("allow-in-data-usage-save".equals(name) && allowAll) {
540                     String pkgname = parser.getAttributeValue(null, "package");
541                     if (pkgname == null) {
542                         Slog.w(TAG, "<allow-in-data-usage-save> without package in " + permFile
543                                 + " at " + parser.getPositionDescription());
544                     } else {
545                         mAllowInDataUsageSave.add(pkgname);
546                     }
547                     XmlUtils.skipCurrentTag(parser);
548                     continue;
549 
550                 } else if ("allow-unthrottled-location".equals(name) && allowAll) {
551                     String pkgname = parser.getAttributeValue(null, "package");
552                     if (pkgname == null) {
553                         Slog.w(TAG, "<allow-unthrottled-location> without package in "
554                             + permFile + " at " + parser.getPositionDescription());
555                     } else {
556                         mAllowUnthrottledLocation.add(pkgname);
557                     }
558                     XmlUtils.skipCurrentTag(parser);
559                     continue;
560 
561                 } else if ("allow-implicit-broadcast".equals(name) && allowAll) {
562                     String action = parser.getAttributeValue(null, "action");
563                     if (action == null) {
564                         Slog.w(TAG, "<allow-implicit-broadcast> without action in " + permFile
565                                 + " at " + parser.getPositionDescription());
566                     } else {
567                         mAllowImplicitBroadcasts.add(action);
568                     }
569                     XmlUtils.skipCurrentTag(parser);
570                     continue;
571 
572                 } else if ("app-link".equals(name) && allowAppConfigs) {
573                     String pkgname = parser.getAttributeValue(null, "package");
574                     if (pkgname == null) {
575                         Slog.w(TAG, "<app-link> without package in " + permFile + " at "
576                                 + parser.getPositionDescription());
577                     } else {
578                         mLinkedApps.add(pkgname);
579                     }
580                     XmlUtils.skipCurrentTag(parser);
581                 } else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) {
582                     String pkgname = parser.getAttributeValue(null, "package");
583                     if (pkgname == null) {
584                         Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile
585                                 + " at " + parser.getPositionDescription());
586                     } else {
587                         mSystemUserWhitelistedApps.add(pkgname);
588                     }
589                     XmlUtils.skipCurrentTag(parser);
590                 } else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) {
591                     String pkgname = parser.getAttributeValue(null, "package");
592                     if (pkgname == null) {
593                         Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile
594                                 + " at " + parser.getPositionDescription());
595                     } else {
596                         mSystemUserBlacklistedApps.add(pkgname);
597                     }
598                     XmlUtils.skipCurrentTag(parser);
599                 } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) {
600                     String pkgname = parser.getAttributeValue(null, "package");
601                     String clsname = parser.getAttributeValue(null, "class");
602                     if (pkgname == null) {
603                         Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile
604                                 + " at " + parser.getPositionDescription());
605                     } else if (clsname == null) {
606                         Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile
607                                 + " at " + parser.getPositionDescription());
608                     } else {
609                         mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
610                     }
611                     XmlUtils.skipCurrentTag(parser);
612                 } else if ("backup-transport-whitelisted-service".equals(name) && allowFeatures) {
613                     String serviceName = parser.getAttributeValue(null, "service");
614                     if (serviceName == null) {
615                         Slog.w(TAG, "<backup-transport-whitelisted-service> without service in "
616                                 + permFile + " at " + parser.getPositionDescription());
617                     } else {
618                         ComponentName cn = ComponentName.unflattenFromString(serviceName);
619                         if (cn == null) {
620                             Slog.w(TAG,
621                                     "<backup-transport-whitelisted-service> with invalid service name "
622                                     + serviceName + " in "+ permFile
623                                     + " at " + parser.getPositionDescription());
624                         } else {
625                             mBackupTransportWhitelist.add(cn);
626                         }
627                     }
628                     XmlUtils.skipCurrentTag(parser);
629                 } else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name)
630                         && allowAppConfigs) {
631                     String pkgname = parser.getAttributeValue(null, "package");
632                     String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage");
633                     if (pkgname == null || carrierPkgname == null) {
634                         Slog.w(TAG, "<disabled-until-used-preinstalled-carrier-associated-app"
635                                 + " without package or carrierAppPackage in " + permFile + " at "
636                                 + parser.getPositionDescription());
637                     } else {
638                         List<String> associatedPkgs =
639                                 mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(
640                                         carrierPkgname);
641                         if (associatedPkgs == null) {
642                             associatedPkgs = new ArrayList<>();
643                             mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(
644                                     carrierPkgname, associatedPkgs);
645                         }
646                         associatedPkgs.add(pkgname);
647                     }
648                     XmlUtils.skipCurrentTag(parser);
649                 } else if ("disabled-until-used-preinstalled-carrier-app".equals(name)
650                         && allowAppConfigs) {
651                     String pkgname = parser.getAttributeValue(null, "package");
652                     if (pkgname == null) {
653                         Slog.w(TAG,
654                                 "<disabled-until-used-preinstalled-carrier-app> without "
655                                         + "package in " + permFile + " at "
656                                         + parser.getPositionDescription());
657                     } else {
658                         mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname);
659                     }
660                     XmlUtils.skipCurrentTag(parser);
661                 } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
662                     // privapp permissions from system, vendor and product partitions are stored
663                     // separately. This is to prevent xml files in the vendor partition from
664                     // granting permissions to priv apps in the system partition and vice
665                     // versa.
666                     boolean vendor = permFile.toPath().startsWith(
667                             Environment.getVendorDirectory().toPath())
668                             || permFile.toPath().startsWith(
669                                 Environment.getOdmDirectory().toPath());
670                     boolean product = permFile.toPath().startsWith(
671                             Environment.getProductDirectory().toPath());
672                     if (vendor) {
673                         readPrivAppPermissions(parser, mVendorPrivAppPermissions,
674                                 mVendorPrivAppDenyPermissions);
675                     } else if (product) {
676                         readPrivAppPermissions(parser, mProductPrivAppPermissions,
677                                 mProductPrivAppDenyPermissions);
678                     } else {
679                         readPrivAppPermissions(parser, mPrivAppPermissions,
680                                 mPrivAppDenyPermissions);
681                     }
682                 } else if ("oem-permissions".equals(name) && allowOemPermissions) {
683                     readOemPermissions(parser);
684                 } else if ("hidden-api-whitelisted-app".equals(name) && allowApiWhitelisting) {
685                     String pkgname = parser.getAttributeValue(null, "package");
686                     if (pkgname == null) {
687                         Slog.w(TAG, "<hidden-api-whitelisted-app> without package in " + permFile
688                                 + " at " + parser.getPositionDescription());
689                     } else {
690                         mHiddenApiPackageWhitelist.add(pkgname);
691                     }
692                     XmlUtils.skipCurrentTag(parser);
693                 } else {
694                     Slog.w(TAG, "Tag " + name + " is unknown or not allowed in "
695                             + permFile.getParent());
696                     XmlUtils.skipCurrentTag(parser);
697                     continue;
698                 }
699             }
700         } catch (XmlPullParserException e) {
701             Slog.w(TAG, "Got exception parsing permissions.", e);
702         } catch (IOException e) {
703             Slog.w(TAG, "Got exception parsing permissions.", e);
704         } finally {
705             IoUtils.closeQuietly(permReader);
706         }
707 
708         // Some devices can be field-converted to FBE, so offer to splice in
709         // those features if not already defined by the static config
710         if (StorageManager.isFileEncryptedNativeOnly()) {
711             addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
712             addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
713         }
714 
715         // Help legacy devices that may not have updated their static config
716         if (StorageManager.hasAdoptable()) {
717             addFeature(PackageManager.FEATURE_ADOPTABLE_STORAGE, 0);
718         }
719 
720         if (ActivityManager.isLowRamDeviceStatic()) {
721             addFeature(PackageManager.FEATURE_RAM_LOW, 0);
722         } else {
723             addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);
724         }
725 
726         for (String featureName : mUnavailableFeatures) {
727             removeFeature(featureName);
728         }
729     }
730 
addFeature(String name, int version)731     private void addFeature(String name, int version) {
732         FeatureInfo fi = mAvailableFeatures.get(name);
733         if (fi == null) {
734             fi = new FeatureInfo();
735             fi.name = name;
736             fi.version = version;
737             mAvailableFeatures.put(name, fi);
738         } else {
739             fi.version = Math.max(fi.version, version);
740         }
741     }
742 
removeFeature(String name)743     private void removeFeature(String name) {
744         if (mAvailableFeatures.remove(name) != null) {
745             Slog.d(TAG, "Removed unavailable feature " + name);
746         }
747     }
748 
readPermission(XmlPullParser parser, String name)749     void readPermission(XmlPullParser parser, String name)
750             throws IOException, XmlPullParserException {
751         if (mPermissions.containsKey(name)) {
752             throw new IllegalStateException("Duplicate permission definition for " + name);
753         }
754 
755         final boolean perUser = XmlUtils.readBooleanAttribute(parser, "perUser", false);
756         final PermissionEntry perm = new PermissionEntry(name, perUser);
757         mPermissions.put(name, perm);
758 
759         int outerDepth = parser.getDepth();
760         int type;
761         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
762                && (type != XmlPullParser.END_TAG
763                        || parser.getDepth() > outerDepth)) {
764             if (type == XmlPullParser.END_TAG
765                     || type == XmlPullParser.TEXT) {
766                 continue;
767             }
768 
769             String tagName = parser.getName();
770             if ("group".equals(tagName)) {
771                 String gidStr = parser.getAttributeValue(null, "gid");
772                 if (gidStr != null) {
773                     int gid = Process.getGidForName(gidStr);
774                     perm.gids = appendInt(perm.gids, gid);
775                 } else {
776                     Slog.w(TAG, "<group> without gid at "
777                             + parser.getPositionDescription());
778                 }
779             }
780             XmlUtils.skipCurrentTag(parser);
781         }
782     }
783 
readPrivAppPermissions(XmlPullParser parser, ArrayMap<String, ArraySet<String>> grantMap, ArrayMap<String, ArraySet<String>> denyMap)784     private void readPrivAppPermissions(XmlPullParser parser,
785             ArrayMap<String, ArraySet<String>> grantMap,
786             ArrayMap<String, ArraySet<String>> denyMap)
787             throws IOException, XmlPullParserException {
788         String packageName = parser.getAttributeValue(null, "package");
789         if (TextUtils.isEmpty(packageName)) {
790             Slog.w(TAG, "package is required for <privapp-permissions> in "
791                     + parser.getPositionDescription());
792             return;
793         }
794 
795         ArraySet<String> permissions = grantMap.get(packageName);
796         if (permissions == null) {
797             permissions = new ArraySet<>();
798         }
799         ArraySet<String> denyPermissions = denyMap.get(packageName);
800         int depth = parser.getDepth();
801         while (XmlUtils.nextElementWithin(parser, depth)) {
802             String name = parser.getName();
803             if ("permission".equals(name)) {
804                 String permName = parser.getAttributeValue(null, "name");
805                 if (TextUtils.isEmpty(permName)) {
806                     Slog.w(TAG, "name is required for <permission> in "
807                             + parser.getPositionDescription());
808                     continue;
809                 }
810                 permissions.add(permName);
811             } else if ("deny-permission".equals(name)) {
812                 String permName = parser.getAttributeValue(null, "name");
813                 if (TextUtils.isEmpty(permName)) {
814                     Slog.w(TAG, "name is required for <deny-permission> in "
815                             + parser.getPositionDescription());
816                     continue;
817                 }
818                 if (denyPermissions == null) {
819                     denyPermissions = new ArraySet<>();
820                 }
821                 denyPermissions.add(permName);
822             }
823         }
824         grantMap.put(packageName, permissions);
825         if (denyPermissions != null) {
826             denyMap.put(packageName, denyPermissions);
827         }
828     }
829 
readOemPermissions(XmlPullParser parser)830     void readOemPermissions(XmlPullParser parser) throws IOException, XmlPullParserException {
831         final String packageName = parser.getAttributeValue(null, "package");
832         if (TextUtils.isEmpty(packageName)) {
833             Slog.w(TAG, "package is required for <oem-permissions> in "
834                     + parser.getPositionDescription());
835             return;
836         }
837 
838         ArrayMap<String, Boolean> permissions = mOemPermissions.get(packageName);
839         if (permissions == null) {
840             permissions = new ArrayMap<>();
841         }
842         final int depth = parser.getDepth();
843         while (XmlUtils.nextElementWithin(parser, depth)) {
844             final String name = parser.getName();
845             if ("permission".equals(name)) {
846                 final String permName = parser.getAttributeValue(null, "name");
847                 if (TextUtils.isEmpty(permName)) {
848                     Slog.w(TAG, "name is required for <permission> in "
849                             + parser.getPositionDescription());
850                     continue;
851                 }
852                 permissions.put(permName, Boolean.TRUE);
853             } else if ("deny-permission".equals(name)) {
854                 String permName = parser.getAttributeValue(null, "name");
855                 if (TextUtils.isEmpty(permName)) {
856                     Slog.w(TAG, "name is required for <deny-permission> in "
857                             + parser.getPositionDescription());
858                     continue;
859                 }
860                 permissions.put(permName, Boolean.FALSE);
861             }
862         }
863         mOemPermissions.put(packageName, permissions);
864     }
865 }
866