blob: fdcb3b9029e53094a1479a048b6618e9bdc36d64 [file] [log] [blame]
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -07001/*
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
17package com.android.server;
18
19import android.content.pm.FeatureInfo;
20import android.os.*;
21import android.os.Process;
22import android.util.ArrayMap;
23import android.util.ArraySet;
24import android.util.Slog;
25import android.util.SparseArray;
26import android.util.Xml;
27import com.android.internal.util.XmlUtils;
28import org.xmlpull.v1.XmlPullParser;
29import org.xmlpull.v1.XmlPullParserException;
30
31import java.io.File;
32import java.io.FileNotFoundException;
33import java.io.FileReader;
34import java.io.IOException;
35import java.util.HashMap;
36import java.util.HashSet;
37
38import static com.android.internal.util.ArrayUtils.appendInt;
39
40/**
41 * Loads global system configuration info.
42 */
43public class SystemConfig {
44 static final String TAG = "SystemConfig";
45
46 static SystemConfig sInstance;
47
48 // Group-ids that are given to all packages as read from etc/permissions/*.xml.
49 int[] mGlobalGids;
50
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>>();
55
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>();
61
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>();
66
67 public static final class PermissionEntry {
68 public final String name;
69 public int[] gids;
70
71 PermissionEntry(String _name) {
72 name = _name;
73 }
74 }
75
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>();
80
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>();
84
85 public static SystemConfig getInstance() {
86 synchronized (SystemConfig.class) {
87 if (sInstance == null) {
88 sInstance = new SystemConfig();
89 }
90 return sInstance;
91 }
92 }
93
94 public int[] getGlobalGids() {
95 return mGlobalGids;
96 }
97
98 public SparseArray<HashSet<String>> getSystemPermissions() {
99 return mSystemPermissions;
100 }
101
102 public ArrayMap<String, String> getSharedLibraries() {
103 return mSharedLibraries;
104 }
105
106 public HashMap<String, FeatureInfo> getAvailableFeatures() {
107 return mAvailableFeatures;
108 }
109
110 public ArrayMap<String, PermissionEntry> getPermissions() {
111 return mPermissions;
112 }
113
114 public ArraySet<String> getAllowInPowerSave() {
115 return mAllowInPowerSave;
116 }
117
118 SystemConfig() {
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);
130 }
131
132 void readPermissions(File libraryDir, boolean onlyFeatures) {
133 // Read permissions from given directory.
134 if (!libraryDir.exists() || !libraryDir.isDirectory()) {
135 if (!onlyFeatures) {
136 Slog.w(TAG, "No directory " + libraryDir + ", skipping");
137 }
138 return;
139 }
140 if (!libraryDir.canRead()) {
141 Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
142 return;
143 }
144
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")) {
149 continue;
150 }
151
152 if (!f.getPath().endsWith(".xml")) {
153 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
154 continue;
155 }
156 if (!f.canRead()) {
157 Slog.w(TAG, "Permissions library file " + f + " cannot be read");
158 continue;
159 }
160
161 readPermissionsFromXml(f, onlyFeatures);
162 }
163
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);
168 }
169
170 private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
171 FileReader permReader = null;
172 try {
173 permReader = new FileReader(permFile);
174 } catch (FileNotFoundException e) {
175 Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
176 return;
177 }
178
179 try {
180 XmlPullParser parser = Xml.newPullParser();
181 parser.setInput(permReader);
182
183 int type;
184 while ((type=parser.next()) != parser.START_TAG
185 && type != parser.END_DOCUMENT) {
186 ;
187 }
188
189 if (type != parser.START_TAG) {
190 throw new XmlPullParserException("No start tag found");
191 }
192
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'");
196 }
197
198 while (true) {
199 XmlUtils.nextElement(parser);
200 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
201 break;
202 }
203
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);
210 } else {
211 Slog.w(TAG, "<group> without gid at "
212 + parser.getPositionDescription());
213 }
214
215 XmlUtils.skipCurrentTag(parser);
216 continue;
217 } else if ("permission".equals(name) && !onlyFeatures) {
218 String perm = parser.getAttributeValue(null, "name");
219 if (perm == null) {
220 Slog.w(TAG, "<permission> without name at "
221 + parser.getPositionDescription());
222 XmlUtils.skipCurrentTag(parser);
223 continue;
224 }
225 perm = perm.intern();
226 readPermission(parser, perm);
227
228 } else if ("assign-permission".equals(name) && !onlyFeatures) {
229 String perm = parser.getAttributeValue(null, "name");
230 if (perm == null) {
231 Slog.w(TAG, "<assign-permission> without name at "
232 + parser.getPositionDescription());
233 XmlUtils.skipCurrentTag(parser);
234 continue;
235 }
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);
241 continue;
242 }
243 int uid = Process.getUidForName(uidStr);
244 if (uid < 0) {
245 Slog.w(TAG, "<assign-permission> with unknown uid \""
246 + uidStr + "\" at "
247 + parser.getPositionDescription());
248 XmlUtils.skipCurrentTag(parser);
249 continue;
250 }
251 perm = perm.intern();
252 HashSet<String> perms = mSystemPermissions.get(uid);
253 if (perms == null) {
254 perms = new HashSet<String>();
255 mSystemPermissions.put(uid, perms);
256 }
257 perms.add(perm);
258 XmlUtils.skipCurrentTag(parser);
259
260 } else if ("library".equals(name) && !onlyFeatures) {
261 String lname = parser.getAttributeValue(null, "name");
262 String lfile = parser.getAttributeValue(null, "file");
263 if (lname == null) {
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());
269 } else {
270 //Log.i(TAG, "Got library " + lname + " in " + lfile);
271 mSharedLibraries.put(lname, lfile);
272 }
273 XmlUtils.skipCurrentTag(parser);
274 continue;
275
276 } else if ("feature".equals(name)) {
277 String fname = parser.getAttributeValue(null, "name");
278 if (fname == null) {
279 Slog.w(TAG, "<feature> without name at "
280 + parser.getPositionDescription());
281 } else {
282 //Log.i(TAG, "Got feature " + fname);
283 FeatureInfo fi = new FeatureInfo();
284 fi.name = fname;
285 mAvailableFeatures.put(fname, fi);
286 }
287 XmlUtils.skipCurrentTag(parser);
288 continue;
289
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());
295 } else {
296 mAllowInPowerSave.add(pkgname);
297 }
298 XmlUtils.skipCurrentTag(parser);
299 continue;
300
301 } else {
302 XmlUtils.skipCurrentTag(parser);
303 continue;
304 }
305
306 }
307 permReader.close();
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);
312 }
313 }
314
315 void readPermission(XmlPullParser parser, String name)
316 throws IOException, XmlPullParserException {
317
318 name = name.intern();
319
320 PermissionEntry perm = mPermissions.get(name);
321 if (perm == null) {
322 perm = new PermissionEntry(name);
323 mPermissions.put(name, perm);
324 }
325 int outerDepth = parser.getDepth();
326 int type;
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) {
332 continue;
333 }
334
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);
341 } else {
342 Slog.w(TAG, "<group> without gid at "
343 + parser.getPositionDescription());
344 }
345 }
346 XmlUtils.skipCurrentTag(parser);
347 }
348 }
349}