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