blob: 92fbc1e7125ad8ac7ec4f4c19ead9804bbc83334 [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;
28import com.android.internal.util.XmlUtils;
29import org.xmlpull.v1.XmlPullParser;
30import org.xmlpull.v1.XmlPullParserException;
31
32import java.io.File;
33import java.io.FileNotFoundException;
34import java.io.FileReader;
35import java.io.IOException;
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070036
37import static com.android.internal.util.ArrayUtils.appendInt;
38
39/**
40 * Loads global system configuration info.
41 */
42public class SystemConfig {
43 static final String TAG = "SystemConfig";
44
45 static SystemConfig sInstance;
46
47 // Group-ids that are given to all packages as read from etc/permissions/*.xml.
48 int[] mGlobalGids;
49
50 // These are the built-in uid -> permission mappings that were read from the
51 // system configuration files.
Jeff Sharkey9f837a92014-10-24 12:07:24 -070052 final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070053
54 // These are the built-in shared libraries that were read from the
55 // system configuration files. Keys are the library names; strings are the
56 // paths to the libraries.
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -070057 final ArrayMap<String, String> mSharedLibraries = new ArrayMap<>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070058
59 // These are the features this devices supports that were read from the
60 // system configuration files.
Jeff Sharkey9f837a92014-10-24 12:07:24 -070061 final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070062
63 public static final class PermissionEntry {
64 public final String name;
65 public int[] gids;
66
67 PermissionEntry(String _name) {
68 name = _name;
69 }
70 }
71
72 // These are the permission -> gid mappings that were read from the
73 // system configuration files.
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -070074 final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070075
76 // These are the packages that are white-listed to be able to run in the
77 // background while in power save mode, as read from the configuration files.
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -070078 final ArraySet<String> mAllowInPowerSave = new ArraySet<>();
79
80 // These are the app package names that should not allow IME switching.
81 final ArraySet<String> mFixedImeApps = new ArraySet<>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070082
83 public static SystemConfig getInstance() {
84 synchronized (SystemConfig.class) {
85 if (sInstance == null) {
86 sInstance = new SystemConfig();
87 }
88 return sInstance;
89 }
90 }
91
92 public int[] getGlobalGids() {
93 return mGlobalGids;
94 }
95
Jeff Sharkey9f837a92014-10-24 12:07:24 -070096 public SparseArray<ArraySet<String>> getSystemPermissions() {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -070097 return mSystemPermissions;
98 }
99
100 public ArrayMap<String, String> getSharedLibraries() {
101 return mSharedLibraries;
102 }
103
Jeff Sharkey9f837a92014-10-24 12:07:24 -0700104 public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700105 return mAvailableFeatures;
106 }
107
108 public ArrayMap<String, PermissionEntry> getPermissions() {
109 return mPermissions;
110 }
111
112 public ArraySet<String> getAllowInPowerSave() {
113 return mAllowInPowerSave;
114 }
115
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -0700116 public ArraySet<String> getFixedImeApps() {
117 return mFixedImeApps;
118 }
119
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700120 SystemConfig() {
121 // Read configuration from system
122 readPermissions(Environment.buildPath(
123 Environment.getRootDirectory(), "etc", "sysconfig"), false);
124 // Read configuration from the old permissions dir
125 readPermissions(Environment.buildPath(
126 Environment.getRootDirectory(), "etc", "permissions"), false);
127 // Only read features from OEM config
128 readPermissions(Environment.buildPath(
129 Environment.getOemDirectory(), "etc", "sysconfig"), true);
130 readPermissions(Environment.buildPath(
131 Environment.getOemDirectory(), "etc", "permissions"), true);
132 }
133
134 void readPermissions(File libraryDir, boolean onlyFeatures) {
135 // Read permissions from given directory.
136 if (!libraryDir.exists() || !libraryDir.isDirectory()) {
137 if (!onlyFeatures) {
138 Slog.w(TAG, "No directory " + libraryDir + ", skipping");
139 }
140 return;
141 }
142 if (!libraryDir.canRead()) {
143 Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
144 return;
145 }
146
147 // Iterate over the files in the directory and scan .xml files
148 for (File f : libraryDir.listFiles()) {
149 // We'll read platform.xml last
150 if (f.getPath().endsWith("etc/permissions/platform.xml")) {
151 continue;
152 }
153
154 if (!f.getPath().endsWith(".xml")) {
155 Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
156 continue;
157 }
158 if (!f.canRead()) {
159 Slog.w(TAG, "Permissions library file " + f + " cannot be read");
160 continue;
161 }
162
163 readPermissionsFromXml(f, onlyFeatures);
164 }
165
166 // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
167 final File permFile = new File(Environment.getRootDirectory(),
168 "etc/permissions/platform.xml");
169 readPermissionsFromXml(permFile, onlyFeatures);
170 }
171
172 private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
173 FileReader permReader = null;
174 try {
175 permReader = new FileReader(permFile);
176 } catch (FileNotFoundException e) {
177 Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
178 return;
179 }
180
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800181 final boolean lowRam = ActivityManager.isLowRamDeviceStatic();
182
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700183 try {
184 XmlPullParser parser = Xml.newPullParser();
185 parser.setInput(permReader);
186
187 int type;
188 while ((type=parser.next()) != parser.START_TAG
189 && type != parser.END_DOCUMENT) {
190 ;
191 }
192
193 if (type != parser.START_TAG) {
194 throw new XmlPullParserException("No start tag found");
195 }
196
197 if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
198 throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
199 ", expected 'permissions' or 'config'");
200 }
201
202 while (true) {
203 XmlUtils.nextElement(parser);
204 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
205 break;
206 }
207
208 String name = parser.getName();
209 if ("group".equals(name) && !onlyFeatures) {
210 String gidStr = parser.getAttributeValue(null, "gid");
211 if (gidStr != null) {
212 int gid = android.os.Process.getGidForName(gidStr);
213 mGlobalGids = appendInt(mGlobalGids, gid);
214 } else {
215 Slog.w(TAG, "<group> without gid at "
216 + parser.getPositionDescription());
217 }
218
219 XmlUtils.skipCurrentTag(parser);
220 continue;
221 } else if ("permission".equals(name) && !onlyFeatures) {
222 String perm = parser.getAttributeValue(null, "name");
223 if (perm == null) {
224 Slog.w(TAG, "<permission> without name at "
225 + parser.getPositionDescription());
226 XmlUtils.skipCurrentTag(parser);
227 continue;
228 }
229 perm = perm.intern();
230 readPermission(parser, perm);
231
232 } else if ("assign-permission".equals(name) && !onlyFeatures) {
233 String perm = parser.getAttributeValue(null, "name");
234 if (perm == null) {
235 Slog.w(TAG, "<assign-permission> without name at "
236 + parser.getPositionDescription());
237 XmlUtils.skipCurrentTag(parser);
238 continue;
239 }
240 String uidStr = parser.getAttributeValue(null, "uid");
241 if (uidStr == null) {
242 Slog.w(TAG, "<assign-permission> without uid at "
243 + parser.getPositionDescription());
244 XmlUtils.skipCurrentTag(parser);
245 continue;
246 }
247 int uid = Process.getUidForName(uidStr);
248 if (uid < 0) {
249 Slog.w(TAG, "<assign-permission> with unknown uid \""
250 + uidStr + "\" at "
251 + parser.getPositionDescription());
252 XmlUtils.skipCurrentTag(parser);
253 continue;
254 }
255 perm = perm.intern();
Jeff Sharkey9f837a92014-10-24 12:07:24 -0700256 ArraySet<String> perms = mSystemPermissions.get(uid);
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700257 if (perms == null) {
Jeff Sharkey9f837a92014-10-24 12:07:24 -0700258 perms = new ArraySet<String>();
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700259 mSystemPermissions.put(uid, perms);
260 }
261 perms.add(perm);
262 XmlUtils.skipCurrentTag(parser);
263
264 } else if ("library".equals(name) && !onlyFeatures) {
265 String lname = parser.getAttributeValue(null, "name");
266 String lfile = parser.getAttributeValue(null, "file");
267 if (lname == null) {
268 Slog.w(TAG, "<library> without name at "
269 + parser.getPositionDescription());
270 } else if (lfile == null) {
271 Slog.w(TAG, "<library> without file at "
272 + parser.getPositionDescription());
273 } else {
274 //Log.i(TAG, "Got library " + lname + " in " + lfile);
275 mSharedLibraries.put(lname, lfile);
276 }
277 XmlUtils.skipCurrentTag(parser);
278 continue;
279
280 } else if ("feature".equals(name)) {
281 String fname = parser.getAttributeValue(null, "name");
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800282 boolean allowed;
283 if (!lowRam) {
284 allowed = true;
285 } else {
286 String notLowRam = parser.getAttributeValue(null, "notLowRam");
287 allowed = !"true".equals(notLowRam);
288 }
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700289 if (fname == null) {
290 Slog.w(TAG, "<feature> without name at "
291 + parser.getPositionDescription());
Dianne Hackbornc0e4aaa2014-11-14 10:55:50 -0800292 } else if (allowed) {
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700293 //Log.i(TAG, "Got feature " + fname);
294 FeatureInfo fi = new FeatureInfo();
295 fi.name = fname;
296 mAvailableFeatures.put(fname, fi);
297 }
298 XmlUtils.skipCurrentTag(parser);
299 continue;
300
301 } else if ("allow-in-power-save".equals(name)) {
302 String pkgname = parser.getAttributeValue(null, "package");
303 if (pkgname == null) {
304 Slog.w(TAG, "<allow-in-power-save> without package at "
305 + parser.getPositionDescription());
306 } else {
307 mAllowInPowerSave.add(pkgname);
308 }
309 XmlUtils.skipCurrentTag(parser);
310 continue;
311
Dianne Hackbornbb8aa5a2014-09-17 13:20:38 -0700312 } else if ("fixed-ime-app".equals(name)) {
313 String pkgname = parser.getAttributeValue(null, "package");
314 if (pkgname == null) {
315 Slog.w(TAG, "<fixed-ime-app> without package at "
316 + parser.getPositionDescription());
317 } else {
318 mFixedImeApps.add(pkgname);
319 }
320 XmlUtils.skipCurrentTag(parser);
321 continue;
322
Dianne Hackbornbe7c50e2014-06-30 14:43:28 -0700323 } else {
324 XmlUtils.skipCurrentTag(parser);
325 continue;
326 }
327
328 }
329 permReader.close();
330 } catch (XmlPullParserException e) {
331 Slog.w(TAG, "Got execption parsing permissions.", e);
332 } catch (IOException e) {
333 Slog.w(TAG, "Got execption parsing permissions.", e);
334 }
335 }
336
337 void readPermission(XmlPullParser parser, String name)
338 throws IOException, XmlPullParserException {
339
340 name = name.intern();
341
342 PermissionEntry perm = mPermissions.get(name);
343 if (perm == null) {
344 perm = new PermissionEntry(name);
345 mPermissions.put(name, perm);
346 }
347 int outerDepth = parser.getDepth();
348 int type;
349 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
350 && (type != XmlPullParser.END_TAG
351 || parser.getDepth() > outerDepth)) {
352 if (type == XmlPullParser.END_TAG
353 || type == XmlPullParser.TEXT) {
354 continue;
355 }
356
357 String tagName = parser.getName();
358 if ("group".equals(tagName)) {
359 String gidStr = parser.getAttributeValue(null, "gid");
360 if (gidStr != null) {
361 int gid = Process.getGidForName(gidStr);
362 perm.gids = appendInt(perm.gids, gid);
363 } else {
364 Slog.w(TAG, "<group> without gid at "
365 + parser.getPositionDescription());
366 }
367 }
368 XmlUtils.skipCurrentTag(parser);
369 }
370 }
371}