SystemConfig.java revision be7c50e0a14e91330ce13161bc14a33d34ff6aca
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; 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} 350