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