2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server;
19 import android.content.pm.FeatureInfo;
21 import android.os.Process;
22 import android.util.ArrayMap;
23 import android.util.ArraySet;
24 import android.util.Slog;
25 import android.util.SparseArray;
26 import android.util.Xml;
27 import com.android.internal.util.XmlUtils;
28 import org.xmlpull.v1.XmlPullParser;
29 import org.xmlpull.v1.XmlPullParserException;
32 import java.io.FileNotFoundException;
33 import java.io.FileReader;
34 import java.io.IOException;
35 import java.util.HashMap;
36 import java.util.HashSet;
38 import static com.android.internal.util.ArrayUtils.appendInt;
41 * Loads global system configuration info.
43 public class SystemConfig {
44 static final String TAG = "SystemConfig";
46 static SystemConfig sInstance;
48 // Group-ids that are given to all packages as read from etc/permissions/*.xml.
51 // These are the built-in uid -> permission mappings that were read from the
52 // system configuration files.
53 final SparseArray<HashSet<String>> mSystemPermissions =
54 new SparseArray<HashSet<String>>();
56 // These are the built-in shared libraries that were read from the
57 // system configuration files. Keys are the library names; strings are the
58 // paths to the libraries.
59 final ArrayMap<String, String> mSharedLibraries
60 = new ArrayMap<String, String>();
62 // These are the features this devices supports that were read from the
63 // system configuration files.
64 final HashMap<String, FeatureInfo> mAvailableFeatures =
65 new HashMap<String, FeatureInfo>();
67 public static final class PermissionEntry {
68 public final String name;
71 PermissionEntry(String _name) {
76 // These are the permission -> gid mappings that were read from the
77 // system configuration files.
78 final ArrayMap<String, PermissionEntry> mPermissions =
79 new ArrayMap<String, PermissionEntry>();
81 // These are the packages that are white-listed to be able to run in the
82 // background while in power save mode, as read from the configuration files.
83 final ArraySet<String> mAllowInPowerSave = new ArraySet<String>();
85 public static SystemConfig getInstance() {
86 synchronized (SystemConfig.class) {
87 if (sInstance == null) {
88 sInstance = new SystemConfig();
94 public int[] getGlobalGids() {
98 public SparseArray<HashSet<String>> getSystemPermissions() {
99 return mSystemPermissions;
102 public ArrayMap<String, String> getSharedLibraries() {
103 return mSharedLibraries;
106 public HashMap<String, FeatureInfo> getAvailableFeatures() {
107 return mAvailableFeatures;
110 public ArrayMap<String, PermissionEntry> getPermissions() {
114 public ArraySet<String> getAllowInPowerSave() {
115 return mAllowInPowerSave;
119 // Read configuration from system
120 readPermissions(Environment.buildPath(
121 Environment.getRootDirectory(), "etc", "sysconfig"), false);
122 // Read configuration from the old permissions dir
123 readPermissions(Environment.buildPath(
124 Environment.getRootDirectory(), "etc", "permissions"), false);
125 // Only read features from OEM config
126 readPermissions(Environment.buildPath(
127 Environment.getOemDirectory(), "etc", "sysconfig"), true);
128 readPermissions(Environment.buildPath(
129 Environment.getOemDirectory(), "etc", "permissions"), true);
132 void readPermissions(File libraryDir, boolean onlyFeatures) {
133 // Read permissions from given directory.
134 if (!libraryDir.exists() || !libraryDir.isDirectory()) {
136 Slog.w(TAG, "No directory " + libraryDir + ", skipping");
140 if (!libraryDir.canRead()) {
141 Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
145 // Iterate over the files in the directory and scan .xml files
146 for (File f : libraryDir.listFiles()) {
147 // We'll read platform.xml last
148 if (f.getPath().endsWith("etc/permissions/platform.xml")) {
152 if (!f.getPath().endsWith(".xml")) {
153 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
157 Slog.w(TAG, "Permissions library file " + f + " cannot be read");
161 readPermissionsFromXml(f, onlyFeatures);
164 // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
165 final File permFile = new File(Environment.getRootDirectory(),
166 "etc/permissions/platform.xml");
167 readPermissionsFromXml(permFile, onlyFeatures);
170 private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
171 FileReader permReader = null;
173 permReader = new FileReader(permFile);
174 } catch (FileNotFoundException e) {
175 Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
180 XmlPullParser parser = Xml.newPullParser();
181 parser.setInput(permReader);
184 while ((type=parser.next()) != parser.START_TAG
185 && type != parser.END_DOCUMENT) {
189 if (type != parser.START_TAG) {
190 throw new XmlPullParserException("No start tag found");
193 if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
194 throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
195 ", expected 'permissions' or 'config'");
199 XmlUtils.nextElement(parser);
200 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
204 String name = parser.getName();
205 if ("group".equals(name) && !onlyFeatures) {
206 String gidStr = parser.getAttributeValue(null, "gid");
207 if (gidStr != null) {
208 int gid = android.os.Process.getGidForName(gidStr);
209 mGlobalGids = appendInt(mGlobalGids, gid);
211 Slog.w(TAG, "<group> without gid at "
212 + parser.getPositionDescription());
215 XmlUtils.skipCurrentTag(parser);
217 } else if ("permission".equals(name) && !onlyFeatures) {
218 String perm = parser.getAttributeValue(null, "name");
220 Slog.w(TAG, "<permission> without name at "
221 + parser.getPositionDescription());
222 XmlUtils.skipCurrentTag(parser);
225 perm = perm.intern();
226 readPermission(parser, perm);
228 } else if ("assign-permission".equals(name) && !onlyFeatures) {
229 String perm = parser.getAttributeValue(null, "name");
231 Slog.w(TAG, "<assign-permission> without name at "
232 + parser.getPositionDescription());
233 XmlUtils.skipCurrentTag(parser);
236 String uidStr = parser.getAttributeValue(null, "uid");
237 if (uidStr == null) {
238 Slog.w(TAG, "<assign-permission> without uid at "
239 + parser.getPositionDescription());
240 XmlUtils.skipCurrentTag(parser);
243 int uid = Process.getUidForName(uidStr);
245 Slog.w(TAG, "<assign-permission> with unknown uid \""
247 + parser.getPositionDescription());
248 XmlUtils.skipCurrentTag(parser);
251 perm = perm.intern();
252 HashSet<String> perms = mSystemPermissions.get(uid);
254 perms = new HashSet<String>();
255 mSystemPermissions.put(uid, perms);
258 XmlUtils.skipCurrentTag(parser);
260 } else if ("library".equals(name) && !onlyFeatures) {
261 String lname = parser.getAttributeValue(null, "name");
262 String lfile = parser.getAttributeValue(null, "file");
264 Slog.w(TAG, "<library> without name at "
265 + parser.getPositionDescription());
266 } else if (lfile == null) {
267 Slog.w(TAG, "<library> without file at "
268 + parser.getPositionDescription());
270 //Log.i(TAG, "Got library " + lname + " in " + lfile);
271 mSharedLibraries.put(lname, lfile);
273 XmlUtils.skipCurrentTag(parser);
276 } else if ("feature".equals(name)) {
277 String fname = parser.getAttributeValue(null, "name");
279 Slog.w(TAG, "<feature> without name at "
280 + parser.getPositionDescription());
282 //Log.i(TAG, "Got feature " + fname);
283 FeatureInfo fi = new FeatureInfo();
285 mAvailableFeatures.put(fname, fi);
287 XmlUtils.skipCurrentTag(parser);
290 } else if ("allow-in-power-save".equals(name)) {
291 String pkgname = parser.getAttributeValue(null, "package");
292 if (pkgname == null) {
293 Slog.w(TAG, "<allow-in-power-save> without package at "
294 + parser.getPositionDescription());
296 mAllowInPowerSave.add(pkgname);
298 XmlUtils.skipCurrentTag(parser);
302 XmlUtils.skipCurrentTag(parser);
308 } catch (XmlPullParserException e) {
309 Slog.w(TAG, "Got execption parsing permissions.", e);
310 } catch (IOException e) {
311 Slog.w(TAG, "Got execption parsing permissions.", e);
315 void readPermission(XmlPullParser parser, String name)
316 throws IOException, XmlPullParserException {
318 name = name.intern();
320 PermissionEntry perm = mPermissions.get(name);
322 perm = new PermissionEntry(name);
323 mPermissions.put(name, perm);
325 int outerDepth = parser.getDepth();
327 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
328 && (type != XmlPullParser.END_TAG
329 || parser.getDepth() > outerDepth)) {
330 if (type == XmlPullParser.END_TAG
331 || type == XmlPullParser.TEXT) {
335 String tagName = parser.getName();
336 if ("group".equals(tagName)) {
337 String gidStr = parser.getAttributeValue(null, "gid");
338 if (gidStr != null) {
339 int gid = Process.getGidForName(gidStr);
340 perm.gids = appendInt(perm.gids, gid);
342 Slog.w(TAG, "<group> without gid at "
343 + parser.getPositionDescription());
346 XmlUtils.skipCurrentTag(parser);