blob: 6ad128c982c4be11b7ab9b336d828cac63a529f4 [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
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -080019import android.app.ActivityManager;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070020import android.content.pm.FeatureInfo;
21import android.os.*;
22import android.os.Process;
23import android.util.ArrayMap;
24import android.util.ArraySet;
25import android.util.Slog;
26import android.util.SparseArray;
27import android.util.Xml;
Jeff Sharkey1c4ae802014-12-19 11:08:55 -080028
29import libcore.io.IoUtils;
30
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070031import com.android.internal.util.XmlUtils;
Jeff Sharkey1c4ae802014-12-19 11:08:55 -080032
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070033import org.xmlpull.v1.XmlPullParser;
34import org.xmlpull.v1.XmlPullParserException;
35
36import java.io.File;
37import java.io.FileNotFoundException;
38import java.io.FileReader;
39import java.io.IOException;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070040
41import static com.android.internal.util.ArrayUtils.appendInt;
42
43/**
44 * Loads global system configuration info.
45 */
46public class SystemConfig {
47 static final String TAG = "SystemConfig";
48
49 static SystemConfig sInstance;
50
51 // Group-ids that are given to all packages as read from etc/permissions/*.xml.
52 int[] mGlobalGids;
53
54 // These are the built-in uid -> permission mappings that were read from the
55 // system configuration files.
Jeff Sharkey9f837a92014-10-24 12:07:24 -070056 final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070057
58 // These are the built-in shared libraries that were read from the
59 // system configuration files. Keys are the library names; strings are the
60 // paths to the libraries.
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -070061 final ArrayMap<String, String> mSharedLibraries = new ArrayMap<>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070062
63 // These are the features this devices supports that were read from the
64 // system configuration files.
Jeff Sharkey9f837a92014-10-24 12:07:24 -070065 final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070066
Jeff Sharkey1c4ae802014-12-19 11:08:55 -080067 // These are the features which this device doesn't support; the OEM
68 // partition uses these to opt-out of features from the system image.
69 final ArraySet<String> mUnavailableFeatures = new ArraySet<>();
70
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070071 public static final class PermissionEntry {
72 public final String name;
73 public int[] gids;
74
75 PermissionEntry(String _name) {
76 name = _name;
77 }
78 }
79
80 // These are the permission -> gid mappings that were read from the
81 // system configuration files.
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -070082 final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070083
84 // These are the packages that are white-listed to be able to run in the
85 // background while in power save mode, as read from the configuration files.
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -070086 final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
87
88 // These are the app package names that should not allow IME switching.
89 final ArraySet<String> mFixedImeApps = new ArraySet<>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070090
91 public static SystemConfig getInstance() {
92 synchronized (SystemConfig.class) {
93 if (sInstance == null) {
94 sInstance = new SystemConfig();
95 }
96 return sInstance;
97 }
98 }
99
100 public int[] getGlobalGids() {
101 return mGlobalGids;
102 }
103
Jeff Sharkey9f837a92014-10-24 12:07:24 -0700104 public SparseArray<ArraySet<String>> getSystemPermissions() {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700105 return mSystemPermissions;
106 }
107
108 public ArrayMap<String, String> getSharedLibraries() {
109 return mSharedLibraries;
110 }
111
Jeff Sharkey9f837a92014-10-24 12:07:24 -0700112 public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700113 return mAvailableFeatures;
114 }
115
116 public ArrayMap<String, PermissionEntry> getPermissions() {
117 return mPermissions;
118 }
119
120 public ArraySet<String> getAllowInPowerSave() {
121 return mAllowInPowerSave;
122 }
123
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -0700124 public ArraySet<String> getFixedImeApps() {
125 return mFixedImeApps;
126 }
127
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700128 SystemConfig() {
129 // Read configuration from system
130 readPermissions(Environment.buildPath(
131 Environment.getRootDirectory(), "etc", "sysconfig"), false);
132 // Read configuration from the old permissions dir
133 readPermissions(Environment.buildPath(
134 Environment.getRootDirectory(), "etc", "permissions"), false);
135 // Only read features from OEM config
136 readPermissions(Environment.buildPath(
137 Environment.getOemDirectory(), "etc", "sysconfig"), true);
138 readPermissions(Environment.buildPath(
139 Environment.getOemDirectory(), "etc", "permissions"), true);
140 }
141
142 void readPermissions(File libraryDir, boolean onlyFeatures) {
143 // Read permissions from given directory.
144 if (!libraryDir.exists() || !libraryDir.isDirectory()) {
145 if (!onlyFeatures) {
146 Slog.w(TAG, "No directory " + libraryDir + ", skipping");
147 }
148 return;
149 }
150 if (!libraryDir.canRead()) {
151 Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
152 return;
153 }
154
155 // Iterate over the files in the directory and scan .xml files
Jeff Sharkey1c4ae802014-12-19 11:08:55 -0800156 File platformFile = null;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700157 for (File f : libraryDir.listFiles()) {
158 // We'll read platform.xml last
159 if (f.getPath().endsWith("etc/permissions/platform.xml")) {
Jeff Sharkey1c4ae802014-12-19 11:08:55 -0800160 platformFile = f;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700161 continue;
162 }
163
164 if (!f.getPath().endsWith(".xml")) {
165 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
166 continue;
167 }
168 if (!f.canRead()) {
169 Slog.w(TAG, "Permissions library file " + f + " cannot be read");
170 continue;
171 }
172
173 readPermissionsFromXml(f, onlyFeatures);
174 }
175
Jeff Sharkey1c4ae802014-12-19 11:08:55 -0800176 // Read platform permissions last so it will take precedence
177 if (platformFile != null) {
178 readPermissionsFromXml(platformFile, onlyFeatures);
179 }
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700180 }
181
182 private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
183 FileReader permReader = null;
184 try {
185 permReader = new FileReader(permFile);
186 } catch (FileNotFoundException e) {
187 Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
188 return;
189 }
190
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800191 final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
192
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700193 try {
194 XmlPullParser parser = Xml.newPullParser();
195 parser.setInput(permReader);
196
197 int type;
198 while ((type=parser.next()) != parser.START_TAG
199 && type != parser.END_DOCUMENT) {
200 ;
201 }
202
203 if (type != parser.START_TAG) {
204 throw new XmlPullParserException("No start tag found");
205 }
206
207 if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800208 throw new XmlPullParserException("Unexpected start tag in " + permFile
209 + ": found " + parser.getName() + ", expected 'permissions' or 'config'");
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700210 }
211
212 while (true) {
213 XmlUtils.nextElement(parser);
214 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
215 break;
216 }
217
218 String name = parser.getName();
219 if ("group".equals(name) && !onlyFeatures) {
220 String gidStr = parser.getAttributeValue(null, "gid");
221 if (gidStr != null) {
222 int gid = android.os.Process.getGidForName(gidStr);
223 mGlobalGids = appendInt(mGlobalGids, gid);
224 } else {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800225 Slog.w(TAG, "<group> without gid in " + permFile + " at "
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700226 + parser.getPositionDescription());
227 }
228
229 XmlUtils.skipCurrentTag(parser);
230 continue;
231 } else if ("permission".equals(name) && !onlyFeatures) {
232 String perm = parser.getAttributeValue(null, "name");
233 if (perm == null) {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800234 Slog.w(TAG, "<permission> without name in " + permFile + " at "
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700235 + parser.getPositionDescription());
236 XmlUtils.skipCurrentTag(parser);
237 continue;
238 }
239 perm = perm.intern();
240 readPermission(parser, perm);
241
242 } else if ("assign-permission".equals(name) && !onlyFeatures) {
243 String perm = parser.getAttributeValue(null, "name");
244 if (perm == null) {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800245 Slog.w(TAG, "<assign-permission> without name in " + permFile + " at "
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700246 + parser.getPositionDescription());
247 XmlUtils.skipCurrentTag(parser);
248 continue;
249 }
250 String uidStr = parser.getAttributeValue(null, "uid");
251 if (uidStr == null) {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800252 Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at "
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700253 + parser.getPositionDescription());
254 XmlUtils.skipCurrentTag(parser);
255 continue;
256 }
257 int uid = Process.getUidForName(uidStr);
258 if (uid < 0) {
259 Slog.w(TAG, "<assign-permission> with unknown uid \""
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800260 + uidStr + " in " + permFile + " at "
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700261 + parser.getPositionDescription());
262 XmlUtils.skipCurrentTag(parser);
263 continue;
264 }
265 perm = perm.intern();
Jeff Sharkey9f837a92014-10-24 12:07:24 -0700266 ArraySet<String> perms = mSystemPermissions.get(uid);
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700267 if (perms == null) {
Jeff Sharkey9f837a92014-10-24 12:07:24 -0700268 perms = new ArraySet<String>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700269 mSystemPermissions.put(uid, perms);
270 }
271 perms.add(perm);
272 XmlUtils.skipCurrentTag(parser);
273
274 } else if ("library".equals(name) && !onlyFeatures) {
275 String lname = parser.getAttributeValue(null, "name");
276 String lfile = parser.getAttributeValue(null, "file");
277 if (lname == null) {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800278 Slog.w(TAG, "<library> without name in " + permFile + " at "
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700279 + parser.getPositionDescription());
280 } else if (lfile == null) {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800281 Slog.w(TAG, "<library> without file in " + permFile + " at "
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700282 + parser.getPositionDescription());
283 } else {
284 //Log.i(TAG, "Got library " + lname + " in " + lfile);
285 mSharedLibraries.put(lname, lfile);
286 }
287 XmlUtils.skipCurrentTag(parser);
288 continue;
289
290 } else if ("feature".equals(name)) {
291 String fname = parser.getAttributeValue(null, "name");
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800292 boolean allowed;
293 if (!lowRam) {
294 allowed = true;
295 } else {
296 String notLowRam = parser.getAttributeValue(null, "notLowRam");
297 allowed = !"true".equals(notLowRam);
298 }
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700299 if (fname == null) {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800300 Slog.w(TAG, "<feature> without name in " + permFile + " at "
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700301 + parser.getPositionDescription());
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800302 } else if (allowed) {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700303 //Log.i(TAG, "Got feature " + fname);
304 FeatureInfo fi = new FeatureInfo();
305 fi.name = fname;
306 mAvailableFeatures.put(fname, fi);
307 }
308 XmlUtils.skipCurrentTag(parser);
309 continue;
310
Jeff Sharkey1c4ae802014-12-19 11:08:55 -0800311 } else if ("unavailable-feature".equals(name)) {
312 String fname = parser.getAttributeValue(null, "name");
313 if (fname == null) {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800314 Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
Jeff Sharkey1c4ae802014-12-19 11:08:55 -0800315 + parser.getPositionDescription());
316 } else {
317 mUnavailableFeatures.add(fname);
318 }
319 XmlUtils.skipCurrentTag(parser);
320 continue;
321
322 } else if ("allow-in-power-save".equals(name) && !onlyFeatures) {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700323 String pkgname = parser.getAttributeValue(null, "package");
324 if (pkgname == null) {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800325 Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700326 + parser.getPositionDescription());
327 } else {
328 mAllowInPowerSave.add(pkgname);
329 }
330 XmlUtils.skipCurrentTag(parser);
331 continue;
332
Jeff Sharkey1c4ae802014-12-19 11:08:55 -0800333 } else if ("fixed-ime-app".equals(name) && !onlyFeatures) {
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -0700334 String pkgname = parser.getAttributeValue(null, "package");
335 if (pkgname == null) {
Dianne Hackbornb3d4cb32015-01-09 09:54:06 -0800336 Slog.w(TAG, "<fixed-ime-app> without package in " + permFile + " at "
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -0700337 + parser.getPositionDescription());
338 } else {
339 mFixedImeApps.add(pkgname);
340 }
341 XmlUtils.skipCurrentTag(parser);
342 continue;
343
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700344 } else {
345 XmlUtils.skipCurrentTag(parser);
346 continue;
347 }
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700348 }
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700349 } catch (XmlPullParserException e) {
Jeff Sharkey1c4ae802014-12-19 11:08:55 -0800350 Slog.w(TAG, "Got exception parsing permissions.", e);
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700351 } catch (IOException e) {
Jeff Sharkey1c4ae802014-12-19 11:08:55 -0800352 Slog.w(TAG, "Got exception parsing permissions.", e);
353 } finally {
354 IoUtils.closeQuietly(permReader);
355 }
356
357 for (String fname : mUnavailableFeatures) {
358 if (mAvailableFeatures.remove(fname) != null) {
359 Slog.d(TAG, "Removed unavailable feature " + fname);
360 }
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700361 }
362 }
363
364 void readPermission(XmlPullParser parser, String name)
365 throws IOException, XmlPullParserException {
366
367 name = name.intern();
368
369 PermissionEntry perm = mPermissions.get(name);
370 if (perm == null) {
371 perm = new PermissionEntry(name);
372 mPermissions.put(name, perm);
373 }
374 int outerDepth = parser.getDepth();
375 int type;
376 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
377 && (type != XmlPullParser.END_TAG
378 || parser.getDepth() > outerDepth)) {
379 if (type == XmlPullParser.END_TAG
380 || type == XmlPullParser.TEXT) {
381 continue;
382 }
383
384 String tagName = parser.getName();
385 if ("group".equals(tagName)) {
386 String gidStr = parser.getAttributeValue(null, "gid");
387 if (gidStr != null) {
388 int gid = Process.getGidForName(gidStr);
389 perm.gids = appendInt(perm.gids, gid);
390 } else {
391 Slog.w(TAG, "<group> without gid at "
392 + parser.getPositionDescription());
393 }
394 }
395 XmlUtils.skipCurrentTag(parser);
396 }
397 }
398}