• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server;
18 
19 import static com.android.internal.util.ArrayUtils.appendInt;
20 
21 import android.app.ActivityManager;
22 import android.content.ComponentName;
23 import android.content.pm.FeatureInfo;
24 import android.content.pm.PackageManager;
25 import android.os.Environment;
26 import android.os.Process;
27 import android.os.storage.StorageManager;
28 import android.text.TextUtils;
29 import android.util.ArrayMap;
30 import android.util.ArraySet;
31 import android.util.Slog;
32 import android.util.SparseArray;
33 import android.util.Xml;
34 
35 import com.android.internal.util.XmlUtils;
36 
37 import libcore.io.IoUtils;
38 
39 import org.xmlpull.v1.XmlPullParser;
40 import org.xmlpull.v1.XmlPullParserException;
41 
42 import java.io.File;
43 import java.io.FileNotFoundException;
44 import java.io.FileReader;
45 import java.io.IOException;
46 import java.util.ArrayList;
47 import java.util.List;
48 
49 /**
50  * Loads global system configuration info.
51  */
52 public class SystemConfig {
53     static final String TAG = "SystemConfig";
54 
55     static SystemConfig sInstance;
56 
57     // permission flag, determines which types of configuration are allowed to be read
58     private static final int ALLOW_FEATURES = 0x01;
59     private static final int ALLOW_LIBS = 0x02;
60     private static final int ALLOW_PERMISSIONS = 0x04;
61     private static final int ALLOW_APP_CONFIGS = 0x08;
62     private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10;
63     private static final int ALLOW_ALL = ~0;
64 
65     // Group-ids that are given to all packages as read from etc/permissions/*.xml.
66     int[] mGlobalGids;
67 
68     // These are the built-in uid -> permission mappings that were read from the
69     // system configuration files.
70     final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
71 
72     // These are the built-in shared libraries that were read from the
73     // system configuration files.  Keys are the library names; strings are the
74     // paths to the libraries.
75     final ArrayMap<String, String> mSharedLibraries  = new ArrayMap<>();
76 
77     // These are the features this devices supports that were read from the
78     // system configuration files.
79     final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
80 
81     // These are the features which this device doesn't support; the OEM
82     // partition uses these to opt-out of features from the system image.
83     final ArraySet<String> mUnavailableFeatures = new ArraySet<>();
84 
85     public static final class PermissionEntry {
86         public final String name;
87         public int[] gids;
88         public boolean perUser;
89 
PermissionEntry(String name, boolean perUser)90         PermissionEntry(String name, boolean perUser) {
91             this.name = name;
92             this.perUser = perUser;
93         }
94     }
95 
96     // These are the permission -> gid mappings that were read from the
97     // system configuration files.
98     final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();
99 
100     // These are the packages that are white-listed to be able to run in the
101     // background while in power save mode (but not whitelisted from device idle modes),
102     // as read from the configuration files.
103     final ArraySet<String> mAllowInPowerSaveExceptIdle = new ArraySet<>();
104 
105     // These are the packages that are white-listed to be able to run in the
106     // background while in power save mode, as read from the configuration files.
107     final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
108 
109     // These are the packages that are white-listed to be able to run in the
110     // background while in data-usage save mode, as read from the configuration files.
111     final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>();
112 
113     // These are the packages that are white-listed to be able to run background location
114     // without throttling, as read from the configuration files.
115     final ArraySet<String> mAllowUnthrottledLocation = new ArraySet<>();
116 
117     // These are the action strings of broadcasts which are whitelisted to
118     // be delivered anonymously even to apps which target O+.
119     final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>();
120 
121     // These are the package names of apps which should be in the 'always'
122     // URL-handling state upon factory reset.
123     final ArraySet<String> mLinkedApps = new ArraySet<>();
124 
125     // These are the packages that are whitelisted to be able to run as system user
126     final ArraySet<String> mSystemUserWhitelistedApps = new ArraySet<>();
127 
128     // These are the packages that should not run under system user
129     final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();
130 
131     // These are the components that are enabled by default as VR mode listener services.
132     final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>();
133 
134     // These are the permitted backup transport service components
135     final ArraySet<ComponentName> mBackupTransportWhitelist = new ArraySet<>();
136 
137     // These are the packages of carrier-associated apps which should be disabled until used until
138     // a SIM is inserted which grants carrier privileges to that carrier app.
139     final ArrayMap<String, List<String>> mDisabledUntilUsedPreinstalledCarrierAssociatedApps =
140             new ArrayMap<>();
141 
142 
143     final ArrayMap<String, ArraySet<String>> mPrivAppPermissions = new ArrayMap<>();
144     final ArrayMap<String, ArraySet<String>> mPrivAppDenyPermissions = new ArrayMap<>();
145 
getInstance()146     public static SystemConfig getInstance() {
147         synchronized (SystemConfig.class) {
148             if (sInstance == null) {
149                 sInstance = new SystemConfig();
150             }
151             return sInstance;
152         }
153     }
154 
getGlobalGids()155     public int[] getGlobalGids() {
156         return mGlobalGids;
157     }
158 
getSystemPermissions()159     public SparseArray<ArraySet<String>> getSystemPermissions() {
160         return mSystemPermissions;
161     }
162 
getSharedLibraries()163     public ArrayMap<String, String> getSharedLibraries() {
164         return mSharedLibraries;
165     }
166 
getAvailableFeatures()167     public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
168         return mAvailableFeatures;
169     }
170 
getPermissions()171     public ArrayMap<String, PermissionEntry> getPermissions() {
172         return mPermissions;
173     }
174 
getAllowImplicitBroadcasts()175     public ArraySet<String> getAllowImplicitBroadcasts() {
176         return mAllowImplicitBroadcasts;
177     }
178 
getAllowInPowerSaveExceptIdle()179     public ArraySet<String> getAllowInPowerSaveExceptIdle() {
180         return mAllowInPowerSaveExceptIdle;
181     }
182 
getAllowInPowerSave()183     public ArraySet<String> getAllowInPowerSave() {
184         return mAllowInPowerSave;
185     }
186 
getAllowInDataUsageSave()187     public ArraySet<String> getAllowInDataUsageSave() {
188         return mAllowInDataUsageSave;
189     }
190 
getAllowUnthrottledLocation()191     public ArraySet<String> getAllowUnthrottledLocation() {
192         return mAllowUnthrottledLocation;
193     }
194 
getLinkedApps()195     public ArraySet<String> getLinkedApps() {
196         return mLinkedApps;
197     }
198 
getSystemUserWhitelistedApps()199     public ArraySet<String> getSystemUserWhitelistedApps() {
200         return mSystemUserWhitelistedApps;
201     }
202 
getSystemUserBlacklistedApps()203     public ArraySet<String> getSystemUserBlacklistedApps() {
204         return mSystemUserBlacklistedApps;
205     }
206 
getDefaultVrComponents()207     public ArraySet<ComponentName> getDefaultVrComponents() {
208         return mDefaultVrComponents;
209     }
210 
getBackupTransportWhitelist()211     public ArraySet<ComponentName> getBackupTransportWhitelist() {
212         return mBackupTransportWhitelist;
213     }
214 
getDisabledUntilUsedPreinstalledCarrierAssociatedApps()215     public ArrayMap<String, List<String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps() {
216         return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;
217     }
218 
getPrivAppPermissions(String packageName)219     public ArraySet<String> getPrivAppPermissions(String packageName) {
220         return mPrivAppPermissions.get(packageName);
221     }
222 
getPrivAppDenyPermissions(String packageName)223     public ArraySet<String> getPrivAppDenyPermissions(String packageName) {
224         return mPrivAppDenyPermissions.get(packageName);
225     }
226 
SystemConfig()227     SystemConfig() {
228         // Read configuration from system
229         readPermissions(Environment.buildPath(
230                 Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
231         // Read configuration from the old permissions dir
232         readPermissions(Environment.buildPath(
233                 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
234         // Allow Vendor to customize system configs around libs, features, permissions and apps
235         int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
236                 ALLOW_APP_CONFIGS;
237         readPermissions(Environment.buildPath(
238                 Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
239         readPermissions(Environment.buildPath(
240                 Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
241         // Allow ODM to customize system configs around libs, features and apps
242         int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
243         readPermissions(Environment.buildPath(
244                 Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
245         readPermissions(Environment.buildPath(
246                 Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
247         // Only allow OEM to customize features
248         readPermissions(Environment.buildPath(
249                 Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
250         readPermissions(Environment.buildPath(
251                 Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
252     }
253 
readPermissions(File libraryDir, int permissionFlag)254     void readPermissions(File libraryDir, int permissionFlag) {
255         // Read permissions from given directory.
256         if (!libraryDir.exists() || !libraryDir.isDirectory()) {
257             if (permissionFlag == ALLOW_ALL) {
258                 Slog.w(TAG, "No directory " + libraryDir + ", skipping");
259             }
260             return;
261         }
262         if (!libraryDir.canRead()) {
263             Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
264             return;
265         }
266 
267         // Iterate over the files in the directory and scan .xml files
268         File platformFile = null;
269         for (File f : libraryDir.listFiles()) {
270             // We'll read platform.xml last
271             if (f.getPath().endsWith("etc/permissions/platform.xml")) {
272                 platformFile = f;
273                 continue;
274             }
275 
276             if (!f.getPath().endsWith(".xml")) {
277                 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
278                 continue;
279             }
280             if (!f.canRead()) {
281                 Slog.w(TAG, "Permissions library file " + f + " cannot be read");
282                 continue;
283             }
284 
285             readPermissionsFromXml(f, permissionFlag);
286         }
287 
288         // Read platform permissions last so it will take precedence
289         if (platformFile != null) {
290             readPermissionsFromXml(platformFile, permissionFlag);
291         }
292     }
293 
readPermissionsFromXml(File permFile, int permissionFlag)294     private void readPermissionsFromXml(File permFile, int permissionFlag) {
295         FileReader permReader = null;
296         try {
297             permReader = new FileReader(permFile);
298         } catch (FileNotFoundException e) {
299             Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
300             return;
301         }
302 
303         final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
304 
305         try {
306             XmlPullParser parser = Xml.newPullParser();
307             parser.setInput(permReader);
308 
309             int type;
310             while ((type=parser.next()) != parser.START_TAG
311                        && type != parser.END_DOCUMENT) {
312                 ;
313             }
314 
315             if (type != parser.START_TAG) {
316                 throw new XmlPullParserException("No start tag found");
317             }
318 
319             if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
320                 throw new XmlPullParserException("Unexpected start tag in " + permFile
321                         + ": found " + parser.getName() + ", expected 'permissions' or 'config'");
322             }
323 
324             boolean allowAll = permissionFlag == ALLOW_ALL;
325             boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
326             boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
327             boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
328             boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
329             boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0;
330             while (true) {
331                 XmlUtils.nextElement(parser);
332                 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
333                     break;
334                 }
335 
336                 String name = parser.getName();
337                 if ("group".equals(name) && allowAll) {
338                     String gidStr = parser.getAttributeValue(null, "gid");
339                     if (gidStr != null) {
340                         int gid = android.os.Process.getGidForName(gidStr);
341                         mGlobalGids = appendInt(mGlobalGids, gid);
342                     } else {
343                         Slog.w(TAG, "<group> without gid in " + permFile + " at "
344                                 + parser.getPositionDescription());
345                     }
346 
347                     XmlUtils.skipCurrentTag(parser);
348                     continue;
349                 } else if ("permission".equals(name) && allowPermissions) {
350                     String perm = parser.getAttributeValue(null, "name");
351                     if (perm == null) {
352                         Slog.w(TAG, "<permission> without name in " + permFile + " at "
353                                 + parser.getPositionDescription());
354                         XmlUtils.skipCurrentTag(parser);
355                         continue;
356                     }
357                     perm = perm.intern();
358                     readPermission(parser, perm);
359 
360                 } else if ("assign-permission".equals(name) && allowPermissions) {
361                     String perm = parser.getAttributeValue(null, "name");
362                     if (perm == null) {
363                         Slog.w(TAG, "<assign-permission> without name in " + permFile + " at "
364                                 + parser.getPositionDescription());
365                         XmlUtils.skipCurrentTag(parser);
366                         continue;
367                     }
368                     String uidStr = parser.getAttributeValue(null, "uid");
369                     if (uidStr == null) {
370                         Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at "
371                                 + parser.getPositionDescription());
372                         XmlUtils.skipCurrentTag(parser);
373                         continue;
374                     }
375                     int uid = Process.getUidForName(uidStr);
376                     if (uid < 0) {
377                         Slog.w(TAG, "<assign-permission> with unknown uid \""
378                                 + uidStr + "  in " + permFile + " at "
379                                 + parser.getPositionDescription());
380                         XmlUtils.skipCurrentTag(parser);
381                         continue;
382                     }
383                     perm = perm.intern();
384                     ArraySet<String> perms = mSystemPermissions.get(uid);
385                     if (perms == null) {
386                         perms = new ArraySet<String>();
387                         mSystemPermissions.put(uid, perms);
388                     }
389                     perms.add(perm);
390                     XmlUtils.skipCurrentTag(parser);
391 
392                 } else if ("library".equals(name) && allowLibs) {
393                     String lname = parser.getAttributeValue(null, "name");
394                     String lfile = parser.getAttributeValue(null, "file");
395                     if (lname == null) {
396                         Slog.w(TAG, "<library> without name in " + permFile + " at "
397                                 + parser.getPositionDescription());
398                     } else if (lfile == null) {
399                         Slog.w(TAG, "<library> without file in " + permFile + " at "
400                                 + parser.getPositionDescription());
401                     } else {
402                         //Log.i(TAG, "Got library " + lname + " in " + lfile);
403                         mSharedLibraries.put(lname, lfile);
404                     }
405                     XmlUtils.skipCurrentTag(parser);
406                     continue;
407 
408                 } else if ("feature".equals(name) && allowFeatures) {
409                     String fname = parser.getAttributeValue(null, "name");
410                     int fversion = XmlUtils.readIntAttribute(parser, "version", 0);
411                     boolean allowed;
412                     if (!lowRam) {
413                         allowed = true;
414                     } else {
415                         String notLowRam = parser.getAttributeValue(null, "notLowRam");
416                         allowed = !"true".equals(notLowRam);
417                     }
418                     if (fname == null) {
419                         Slog.w(TAG, "<feature> without name in " + permFile + " at "
420                                 + parser.getPositionDescription());
421                     } else if (allowed) {
422                         addFeature(fname, fversion);
423                     }
424                     XmlUtils.skipCurrentTag(parser);
425                     continue;
426 
427                 } else if ("unavailable-feature".equals(name) && allowFeatures) {
428                     String fname = parser.getAttributeValue(null, "name");
429                     if (fname == null) {
430                         Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
431                                 + parser.getPositionDescription());
432                     } else {
433                         mUnavailableFeatures.add(fname);
434                     }
435                     XmlUtils.skipCurrentTag(parser);
436                     continue;
437 
438                 } else if ("allow-in-power-save-except-idle".equals(name) && allowAll) {
439                     String pkgname = parser.getAttributeValue(null, "package");
440                     if (pkgname == null) {
441                         Slog.w(TAG, "<allow-in-power-save-except-idle> without package in "
442                                 + permFile + " at " + parser.getPositionDescription());
443                     } else {
444                         mAllowInPowerSaveExceptIdle.add(pkgname);
445                     }
446                     XmlUtils.skipCurrentTag(parser);
447                     continue;
448 
449                 } else if ("allow-in-power-save".equals(name) && allowAll) {
450                     String pkgname = parser.getAttributeValue(null, "package");
451                     if (pkgname == null) {
452                         Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
453                                 + parser.getPositionDescription());
454                     } else {
455                         mAllowInPowerSave.add(pkgname);
456                     }
457                     XmlUtils.skipCurrentTag(parser);
458                     continue;
459 
460                 } else if ("allow-in-data-usage-save".equals(name) && allowAll) {
461                     String pkgname = parser.getAttributeValue(null, "package");
462                     if (pkgname == null) {
463                         Slog.w(TAG, "<allow-in-data-usage-save> without package in " + permFile
464                                 + " at " + parser.getPositionDescription());
465                     } else {
466                         mAllowInDataUsageSave.add(pkgname);
467                     }
468                     XmlUtils.skipCurrentTag(parser);
469                     continue;
470 
471                 } else if ("allow-unthrottled-location".equals(name) && allowAll) {
472                     String pkgname = parser.getAttributeValue(null, "package");
473                     if (pkgname == null) {
474                         Slog.w(TAG, "<allow-unthrottled-location> without package in "
475                             + permFile + " at " + parser.getPositionDescription());
476                     } else {
477                         mAllowUnthrottledLocation.add(pkgname);
478                     }
479                     XmlUtils.skipCurrentTag(parser);
480                     continue;
481 
482                 } else if ("allow-implicit-broadcast".equals(name) && allowAll) {
483                     String action = parser.getAttributeValue(null, "action");
484                     if (action == null) {
485                         Slog.w(TAG, "<allow-implicit-broadcast> without action in " + permFile
486                                 + " at " + parser.getPositionDescription());
487                     } else {
488                         mAllowImplicitBroadcasts.add(action);
489                     }
490                     XmlUtils.skipCurrentTag(parser);
491                     continue;
492 
493                 } else if ("app-link".equals(name) && allowAppConfigs) {
494                     String pkgname = parser.getAttributeValue(null, "package");
495                     if (pkgname == null) {
496                         Slog.w(TAG, "<app-link> without package in " + permFile + " at "
497                                 + parser.getPositionDescription());
498                     } else {
499                         mLinkedApps.add(pkgname);
500                     }
501                     XmlUtils.skipCurrentTag(parser);
502                 } else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) {
503                     String pkgname = parser.getAttributeValue(null, "package");
504                     if (pkgname == null) {
505                         Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile
506                                 + " at " + parser.getPositionDescription());
507                     } else {
508                         mSystemUserWhitelistedApps.add(pkgname);
509                     }
510                     XmlUtils.skipCurrentTag(parser);
511                 } else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) {
512                     String pkgname = parser.getAttributeValue(null, "package");
513                     if (pkgname == null) {
514                         Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile
515                                 + " at " + parser.getPositionDescription());
516                     } else {
517                         mSystemUserBlacklistedApps.add(pkgname);
518                     }
519                     XmlUtils.skipCurrentTag(parser);
520                 } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) {
521                     String pkgname = parser.getAttributeValue(null, "package");
522                     String clsname = parser.getAttributeValue(null, "class");
523                     if (pkgname == null) {
524                         Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile
525                                 + " at " + parser.getPositionDescription());
526                     } else if (clsname == null) {
527                         Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile
528                                 + " at " + parser.getPositionDescription());
529                     } else {
530                         mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
531                     }
532                     XmlUtils.skipCurrentTag(parser);
533                 } else if ("backup-transport-whitelisted-service".equals(name) && allowFeatures) {
534                     String serviceName = parser.getAttributeValue(null, "service");
535                     if (serviceName == null) {
536                         Slog.w(TAG, "<backup-transport-whitelisted-service> without service in "
537                                 + permFile + " at " + parser.getPositionDescription());
538                     } else {
539                         ComponentName cn = ComponentName.unflattenFromString(serviceName);
540                         if (cn == null) {
541                             Slog.w(TAG,
542                                     "<backup-transport-whitelisted-service> with invalid service name "
543                                     + serviceName + " in "+ permFile
544                                     + " at " + parser.getPositionDescription());
545                         } else {
546                             mBackupTransportWhitelist.add(cn);
547                         }
548                     }
549                     XmlUtils.skipCurrentTag(parser);
550                 } else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name)
551                         && allowAppConfigs) {
552                     String pkgname = parser.getAttributeValue(null, "package");
553                     String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage");
554                     if (pkgname == null || carrierPkgname == null) {
555                         Slog.w(TAG, "<disabled-until-used-preinstalled-carrier-associated-app"
556                                 + " without package or carrierAppPackage in " + permFile + " at "
557                                 + parser.getPositionDescription());
558                     } else {
559                         List<String> associatedPkgs =
560                                 mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(
561                                         carrierPkgname);
562                         if (associatedPkgs == null) {
563                             associatedPkgs = new ArrayList<>();
564                             mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(
565                                     carrierPkgname, associatedPkgs);
566                         }
567                         associatedPkgs.add(pkgname);
568                     }
569                     XmlUtils.skipCurrentTag(parser);
570                 } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
571                     readPrivAppPermissions(parser);
572                 } else {
573                     XmlUtils.skipCurrentTag(parser);
574                     continue;
575                 }
576             }
577         } catch (XmlPullParserException e) {
578             Slog.w(TAG, "Got exception parsing permissions.", e);
579         } catch (IOException e) {
580             Slog.w(TAG, "Got exception parsing permissions.", e);
581         } finally {
582             IoUtils.closeQuietly(permReader);
583         }
584 
585         // Some devices can be field-converted to FBE, so offer to splice in
586         // those features if not already defined by the static config
587         if (StorageManager.isFileEncryptedNativeOnly()) {
588             addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);
589             addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);
590         }
591 
592         if (ActivityManager.isLowRamDeviceStatic()) {
593             addFeature(PackageManager.FEATURE_RAM_LOW, 0);
594         } else {
595             addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);
596         }
597 
598         for (String featureName : mUnavailableFeatures) {
599             removeFeature(featureName);
600         }
601     }
602 
addFeature(String name, int version)603     private void addFeature(String name, int version) {
604         FeatureInfo fi = mAvailableFeatures.get(name);
605         if (fi == null) {
606             fi = new FeatureInfo();
607             fi.name = name;
608             fi.version = version;
609             mAvailableFeatures.put(name, fi);
610         } else {
611             fi.version = Math.max(fi.version, version);
612         }
613     }
614 
removeFeature(String name)615     private void removeFeature(String name) {
616         if (mAvailableFeatures.remove(name) != null) {
617             Slog.d(TAG, "Removed unavailable feature " + name);
618         }
619     }
620 
readPermission(XmlPullParser parser, String name)621     void readPermission(XmlPullParser parser, String name)
622             throws IOException, XmlPullParserException {
623         if (mPermissions.containsKey(name)) {
624             throw new IllegalStateException("Duplicate permission definition for " + name);
625         }
626 
627         final boolean perUser = XmlUtils.readBooleanAttribute(parser, "perUser", false);
628         final PermissionEntry perm = new PermissionEntry(name, perUser);
629         mPermissions.put(name, perm);
630 
631         int outerDepth = parser.getDepth();
632         int type;
633         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
634                && (type != XmlPullParser.END_TAG
635                        || parser.getDepth() > outerDepth)) {
636             if (type == XmlPullParser.END_TAG
637                     || type == XmlPullParser.TEXT) {
638                 continue;
639             }
640 
641             String tagName = parser.getName();
642             if ("group".equals(tagName)) {
643                 String gidStr = parser.getAttributeValue(null, "gid");
644                 if (gidStr != null) {
645                     int gid = Process.getGidForName(gidStr);
646                     perm.gids = appendInt(perm.gids, gid);
647                 } else {
648                     Slog.w(TAG, "<group> without gid at "
649                             + parser.getPositionDescription());
650                 }
651             }
652             XmlUtils.skipCurrentTag(parser);
653         }
654     }
655 
readPrivAppPermissions(XmlPullParser parser)656     void readPrivAppPermissions(XmlPullParser parser) throws IOException, XmlPullParserException {
657         String packageName = parser.getAttributeValue(null, "package");
658         if (TextUtils.isEmpty(packageName)) {
659             Slog.w(TAG, "package is required for <privapp-permissions> in "
660                     + parser.getPositionDescription());
661             return;
662         }
663 
664         ArraySet<String> permissions = mPrivAppPermissions.get(packageName);
665         if (permissions == null) {
666             permissions = new ArraySet<>();
667         }
668         ArraySet<String> denyPermissions = mPrivAppDenyPermissions.get(packageName);
669         int depth = parser.getDepth();
670         while (XmlUtils.nextElementWithin(parser, depth)) {
671             String name = parser.getName();
672             if ("permission".equals(name)) {
673                 String permName = parser.getAttributeValue(null, "name");
674                 if (TextUtils.isEmpty(permName)) {
675                     Slog.w(TAG, "name is required for <permission> in "
676                             + parser.getPositionDescription());
677                     continue;
678                 }
679                 permissions.add(permName);
680             } else if ("deny-permission".equals(name)) {
681                 String permName = parser.getAttributeValue(null, "name");
682                 if (TextUtils.isEmpty(permName)) {
683                     Slog.w(TAG, "name is required for <deny-permission> in "
684                             + parser.getPositionDescription());
685                     continue;
686                 }
687                 if (denyPermissions == null) {
688                     denyPermissions = new ArraySet<>();
689                 }
690                 denyPermissions.add(permName);
691             }
692         }
693         mPrivAppPermissions.put(packageName, permissions);
694         if (denyPermissions != null) {
695             mPrivAppDenyPermissions.put(packageName, denyPermissions);
696         }
697     }
698 }
699