SystemConfig.java revision c0e4aaad1ecd5df2608f10a644f3d8f60056d94c
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 17package com.android.server; 18 19import android.app.ActivityManager; 20import 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; 36 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. 52 final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>(); 53 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. 57 final ArrayMap<String, String> mSharedLibraries = new ArrayMap<>(); 58 59 // These are the features this devices supports that were read from the 60 // system configuration files. 61 final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>(); 62 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. 74 final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>(); 75 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. 78 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<>(); 82 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 96 public SparseArray<ArraySet<String>> getSystemPermissions() { 97 return mSystemPermissions; 98 } 99 100 public ArrayMap<String, String> getSharedLibraries() { 101 return mSharedLibraries; 102 } 103 104 public ArrayMap<String, FeatureInfo> getAvailableFeatures() { 105 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 116 public ArraySet<String> getFixedImeApps() { 117 return mFixedImeApps; 118 } 119 120 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 181 final boolean lowRam = ActivityManager.isLowRamDeviceStatic(); 182 183 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(); 256 ArraySet<String> perms = mSystemPermissions.get(uid); 257 if (perms == null) { 258 perms = new ArraySet<String>(); 259 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"); 282 boolean allowed; 283 if (!lowRam) { 284 allowed = true; 285 } else { 286 String notLowRam = parser.getAttributeValue(null, "notLowRam"); 287 allowed = !"true".equals(notLowRam); 288 } 289 if (fname == null) { 290 Slog.w(TAG, "<feature> without name at " 291 + parser.getPositionDescription()); 292 } else if (allowed) { 293 //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 312 } 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 323 } 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} 372