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