OSDN Git Service

Add network access blocking when in battery save mode.
authorDianne Hackborn <hackbod@google.com>
Mon, 30 Jun 2014 21:43:28 +0000 (14:43 -0700)
committerDianne Hackborn <hackbod@google.com>
Tue, 1 Jul 2014 16:22:57 +0000 (09:22 -0700)
The network policy manager now monitors battery save mode and,
when in battery save, uses its facility to block access to metered
networks to block access to all networks.  That is, it tells the
network management service that all networks have an (infinite)
quota, and puts various app uids to be restricted under quota
interfaces as appropriate.

This new network blocking needs a new facility to be able to white
list apps, such as GmsCore.  To do this, I refactored the package
manager's permission configuration stuff into a separate SystemConfig
class that can be used by others, and it now has a new tag to
specify package names that should be white-listed for power save
mode.  These are retrieved by the network policy manager and used
to build a whitelist of uids.

The new general config files can now go in system/etc/config,
though currently everything still remains in the permissions dir.

Still left to be done is changing the semantics of what uids are
allowed in this mode, to include all perceptable uids.  (So that we
can still do things like background music playback.)  This will be
done in a follow-on CL.

Change-Id: I9bb7029f61dae62e6236da5ca60765439f8d76d2

core/java/android/net/INetworkPolicyManager.aidl
core/java/android/net/NetworkPolicyManager.java
data/etc/platform.xml
services/core/java/com/android/server/SystemConfig.java [new file with mode: 0644]
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/net/NetworkPolicyManagerService.java
services/core/java/com/android/server/pm/PackageManagerService.java
services/java/com/android/server/SystemServer.java

index df6057e..1129c9e 100644 (file)
@@ -31,11 +31,15 @@ interface INetworkPolicyManager {
 
     /** Control UID policies. */
     void setUidPolicy(int uid, int policy);
+    void addUidPolicy(int uid, int policy);
+    void removeUidPolicy(int uid, int policy);
     int getUidPolicy(int uid);
     int[] getUidsWithPolicy(int policy);
 
     boolean isUidForeground(int uid);
 
+    int[] getPowerSaveAppIdWhitelist();
+
     void registerListener(INetworkPolicyListener listener);
     void unregisterListener(INetworkPolicyListener listener);
 
index 2cd1f9b..a8e7757 100644 (file)
@@ -45,6 +45,8 @@ public class NetworkPolicyManager {
     public static final int POLICY_NONE = 0x0;
     /** Reject network usage on metered networks when application in background. */
     public static final int POLICY_REJECT_METERED_BACKGROUND = 0x1;
+    /** Allow network use (metered or not) in the background in battery save mode. */
+    public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
 
     /** All network traffic should be allowed. */
     public static final int RULE_ALLOW_ALL = 0x0;
@@ -76,7 +78,7 @@ public class NetworkPolicyManager {
      * Set policy flags for specific UID.
      *
      * @param policy {@link #POLICY_NONE} or combination of flags like
-     *            {@link #POLICY_REJECT_METERED_BACKGROUND}.
+     * {@link #POLICY_REJECT_METERED_BACKGROUND}, {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
      */
     public void setUidPolicy(int uid, int policy) {
         try {
@@ -85,6 +87,30 @@ public class NetworkPolicyManager {
         }
     }
 
+    /**
+     * Add policy flags for specific UID.  The given policy bits will be set for
+     * the uid.  Policy flags may be either
+     * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+     */
+    public void addUidPolicy(int uid, int policy) {
+        try {
+            mService.addUidPolicy(uid, policy);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Clear/remove policy flags for specific UID.  The given policy bits will be set for
+     * the uid.  Policy flags may be either
+     * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+     */
+    public void removeUidPolicy(int uid, int policy) {
+        try {
+            mService.removeUidPolicy(uid, policy);
+        } catch (RemoteException e) {
+        }
+    }
+
     public int getUidPolicy(int uid) {
         try {
             return mService.getUidPolicy(uid);
@@ -101,6 +127,14 @@ public class NetworkPolicyManager {
         }
     }
 
+    public int[] getPowerSaveAppIdWhitelist() {
+        try {
+            return mService.getPowerSaveAppIdWhitelist();
+        } catch (RemoteException e) {
+            return new int[0];
+        }
+    }
+
     public void registerListener(INetworkPolicyListener listener) {
         try {
             mService.registerListener(listener);
index 3857ec0..91f5896 100644 (file)
     <library name="javax.obex"
             file="/system/framework/javax.obex.jar"/>
 
+    <!-- These are the standard packages that are white-listed to always have internet
+         access while in power save mode, even if they aren't in the foreground. -->
+    <allow-in-power-save package="com.android.providers.downloads" />
+
 </permissions>
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
new file mode 100644 (file)
index 0000000..fdcb3b9
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.pm.FeatureInfo;
+import android.os.*;
+import android.os.Process;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
+import com.android.internal.util.XmlUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import static com.android.internal.util.ArrayUtils.appendInt;
+
+/**
+ * Loads global system configuration info.
+ */
+public class SystemConfig {
+    static final String TAG = "SystemConfig";
+
+    static SystemConfig sInstance;
+
+    // Group-ids that are given to all packages as read from etc/permissions/*.xml.
+    int[] mGlobalGids;
+
+    // These are the built-in uid -> permission mappings that were read from the
+    // system configuration files.
+    final SparseArray<HashSet<String>> mSystemPermissions =
+            new SparseArray<HashSet<String>>();
+
+    // These are the built-in shared libraries that were read from the
+    // system configuration files.  Keys are the library names; strings are the
+    // paths to the libraries.
+    final ArrayMap<String, String> mSharedLibraries
+            = new ArrayMap<String, String>();
+
+    // These are the features this devices supports that were read from the
+    // system configuration files.
+    final HashMap<String, FeatureInfo> mAvailableFeatures =
+            new HashMap<String, FeatureInfo>();
+
+    public static final class PermissionEntry {
+        public final String name;
+        public int[] gids;
+
+        PermissionEntry(String _name) {
+            name = _name;
+        }
+    }
+
+    // These are the permission -> gid mappings that were read from the
+    // system configuration files.
+    final ArrayMap<String, PermissionEntry> mPermissions =
+            new ArrayMap<String, PermissionEntry>();
+
+    // These are the packages that are white-listed to be able to run in the
+    // background while in power save mode, as read from the configuration files.
+    final ArraySet<String> mAllowInPowerSave = new ArraySet<String>();
+
+    public static SystemConfig getInstance() {
+        synchronized (SystemConfig.class) {
+            if (sInstance == null) {
+                sInstance = new SystemConfig();
+            }
+            return sInstance;
+        }
+    }
+
+    public int[] getGlobalGids() {
+        return mGlobalGids;
+    }
+
+    public SparseArray<HashSet<String>> getSystemPermissions() {
+        return mSystemPermissions;
+    }
+
+    public ArrayMap<String, String> getSharedLibraries() {
+        return mSharedLibraries;
+    }
+
+    public HashMap<String, FeatureInfo> getAvailableFeatures() {
+        return mAvailableFeatures;
+    }
+
+    public ArrayMap<String, PermissionEntry> getPermissions() {
+        return mPermissions;
+    }
+
+    public ArraySet<String> getAllowInPowerSave() {
+        return mAllowInPowerSave;
+    }
+
+    SystemConfig() {
+        // Read configuration from system
+        readPermissions(Environment.buildPath(
+                Environment.getRootDirectory(), "etc", "sysconfig"), false);
+        // Read configuration from the old permissions dir
+        readPermissions(Environment.buildPath(
+                Environment.getRootDirectory(), "etc", "permissions"), false);
+        // Only read features from OEM config
+        readPermissions(Environment.buildPath(
+                Environment.getOemDirectory(), "etc", "sysconfig"), true);
+        readPermissions(Environment.buildPath(
+                Environment.getOemDirectory(), "etc", "permissions"), true);
+    }
+
+    void readPermissions(File libraryDir, boolean onlyFeatures) {
+        // Read permissions from given directory.
+        if (!libraryDir.exists() || !libraryDir.isDirectory()) {
+            if (!onlyFeatures) {
+                Slog.w(TAG, "No directory " + libraryDir + ", skipping");
+            }
+            return;
+        }
+        if (!libraryDir.canRead()) {
+            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
+            return;
+        }
+
+        // Iterate over the files in the directory and scan .xml files
+        for (File f : libraryDir.listFiles()) {
+            // We'll read platform.xml last
+            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
+                continue;
+            }
+
+            if (!f.getPath().endsWith(".xml")) {
+                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
+                continue;
+            }
+            if (!f.canRead()) {
+                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
+                continue;
+            }
+
+            readPermissionsFromXml(f, onlyFeatures);
+        }
+
+        // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
+        final File permFile = new File(Environment.getRootDirectory(),
+                "etc/permissions/platform.xml");
+        readPermissionsFromXml(permFile, onlyFeatures);
+    }
+
+    private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
+        FileReader permReader = null;
+        try {
+            permReader = new FileReader(permFile);
+        } catch (FileNotFoundException e) {
+            Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
+            return;
+        }
+
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(permReader);
+
+            int type;
+            while ((type=parser.next()) != parser.START_TAG
+                       && type != parser.END_DOCUMENT) {
+                ;
+            }
+
+            if (type != parser.START_TAG) {
+                throw new XmlPullParserException("No start tag found");
+            }
+
+            if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
+                throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
+                        ", expected 'permissions' or 'config'");
+            }
+
+            while (true) {
+                XmlUtils.nextElement(parser);
+                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                    break;
+                }
+
+                String name = parser.getName();
+                if ("group".equals(name) && !onlyFeatures) {
+                    String gidStr = parser.getAttributeValue(null, "gid");
+                    if (gidStr != null) {
+                        int gid = android.os.Process.getGidForName(gidStr);
+                        mGlobalGids = appendInt(mGlobalGids, gid);
+                    } else {
+                        Slog.w(TAG, "<group> without gid at "
+                                + parser.getPositionDescription());
+                    }
+
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                } else if ("permission".equals(name) && !onlyFeatures) {
+                    String perm = parser.getAttributeValue(null, "name");
+                    if (perm == null) {
+                        Slog.w(TAG, "<permission> without name at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    perm = perm.intern();
+                    readPermission(parser, perm);
+
+                } else if ("assign-permission".equals(name) && !onlyFeatures) {
+                    String perm = parser.getAttributeValue(null, "name");
+                    if (perm == null) {
+                        Slog.w(TAG, "<assign-permission> without name at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    String uidStr = parser.getAttributeValue(null, "uid");
+                    if (uidStr == null) {
+                        Slog.w(TAG, "<assign-permission> without uid at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    int uid = Process.getUidForName(uidStr);
+                    if (uid < 0) {
+                        Slog.w(TAG, "<assign-permission> with unknown uid \""
+                                + uidStr + "\" at "
+                                + parser.getPositionDescription());
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    perm = perm.intern();
+                    HashSet<String> perms = mSystemPermissions.get(uid);
+                    if (perms == null) {
+                        perms = new HashSet<String>();
+                        mSystemPermissions.put(uid, perms);
+                    }
+                    perms.add(perm);
+                    XmlUtils.skipCurrentTag(parser);
+
+                } else if ("library".equals(name) && !onlyFeatures) {
+                    String lname = parser.getAttributeValue(null, "name");
+                    String lfile = parser.getAttributeValue(null, "file");
+                    if (lname == null) {
+                        Slog.w(TAG, "<library> without name at "
+                                + parser.getPositionDescription());
+                    } else if (lfile == null) {
+                        Slog.w(TAG, "<library> without file at "
+                                + parser.getPositionDescription());
+                    } else {
+                        //Log.i(TAG, "Got library " + lname + " in " + lfile);
+                        mSharedLibraries.put(lname, lfile);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("feature".equals(name)) {
+                    String fname = parser.getAttributeValue(null, "name");
+                    if (fname == null) {
+                        Slog.w(TAG, "<feature> without name at "
+                                + parser.getPositionDescription());
+                    } else {
+                        //Log.i(TAG, "Got feature " + fname);
+                        FeatureInfo fi = new FeatureInfo();
+                        fi.name = fname;
+                        mAvailableFeatures.put(fname, fi);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else if ("allow-in-power-save".equals(name)) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<allow-in-power-save> without package at "
+                                + parser.getPositionDescription());
+                    } else {
+                        mAllowInPowerSave.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+
+                } else {
+                    XmlUtils.skipCurrentTag(parser);
+                    continue;
+                }
+
+            }
+            permReader.close();
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "Got execption parsing permissions.", e);
+        } catch (IOException e) {
+            Slog.w(TAG, "Got execption parsing permissions.", e);
+        }
+    }
+
+    void readPermission(XmlPullParser parser, String name)
+            throws IOException, XmlPullParserException {
+
+        name = name.intern();
+
+        PermissionEntry perm = mPermissions.get(name);
+        if (perm == null) {
+            perm = new PermissionEntry(name);
+            mPermissions.put(name, perm);
+        }
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+               && (type != XmlPullParser.END_TAG
+                       || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG
+                    || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if ("group".equals(tagName)) {
+                String gidStr = parser.getAttributeValue(null, "gid");
+                if (gidStr != null) {
+                    int gid = Process.getGidForName(gidStr);
+                    perm.gids = appendInt(perm.gids, gid);
+                } else {
+                    Slog.w(TAG, "<group> without gid at "
+                            + parser.getPositionDescription());
+                }
+            }
+            XmlUtils.skipCurrentTag(parser);
+        }
+    }
+}
index 933046b..17268c3 100644 (file)
@@ -36,9 +36,6 @@ import android.app.IActivityContainerCallback;
 import android.app.IAppTask;
 import android.app.admin.DevicePolicyManager;
 import android.appwidget.AppWidgetManager;
-import android.content.DialogInterface.OnClickListener;
-import android.content.res.Resources;
-import android.graphics.BitmapFactory;
 import android.graphics.Rect;
 import android.os.BatteryStats;
 import android.os.PersistableBundle;
@@ -174,12 +171,8 @@ import android.os.SystemProperties;
 import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.text.Spannable;
-import android.text.SpannableString;
 import android.text.format.DateUtils;
 import android.text.format.Time;
-import android.text.style.DynamicDrawableSpan;
-import android.text.style.ImageSpan;
 import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Log;
@@ -193,7 +186,6 @@ import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
-import android.widget.TextView;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
index 416a6b1..142094f 100644 (file)
@@ -39,6 +39,7 @@ import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
@@ -111,6 +112,7 @@ import android.os.INetworkManagementService;
 import android.os.IPowerManager;
 import android.os.Message;
 import android.os.MessageQueue.IdleHandler;
+import android.os.PowerManagerInternal;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -119,6 +121,8 @@ import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.text.format.Formatter;
 import android.text.format.Time;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Log;
 import android.util.NtpTrustedTime;
@@ -133,6 +137,8 @@ import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.LocalServices;
+import com.android.server.SystemConfig;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 import com.google.android.collect.Sets;
@@ -153,7 +159,6 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 
 import libcore.io.IoUtils;
@@ -240,35 +245,43 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
 
     private IConnectivityManager mConnManager;
     private INotificationManager mNotifManager;
+    private PowerManagerInternal mPowerManagerInternal;
 
     private final Object mRulesLock = new Object();
 
     private volatile boolean mScreenOn;
     private volatile boolean mRestrictBackground;
+    private volatile boolean mRestrictPower;
 
     private final boolean mSuppressDefaultPolicy;
 
     /** Defined network policies. */
-    private HashMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = Maps.newHashMap();
+    private final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<
+            NetworkTemplate, NetworkPolicy>();
     /** Currently active network rules for ifaces. */
-    private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
+    private final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<
+            NetworkPolicy, String[]>();
 
     /** Defined UID policies. */
-    private SparseIntArray mUidPolicy = new SparseIntArray();
+    private final SparseIntArray mUidPolicy = new SparseIntArray();
     /** Currently derived rules for each UID. */
-    private SparseIntArray mUidRules = new SparseIntArray();
+    private final SparseIntArray mUidRules = new SparseIntArray();
+
+    /** UIDs that have been white-listed to always be able to have network access in
+     * power save mode. */
+    private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
 
     /** Set of ifaces that are metered. */
     private HashSet<String> mMeteredIfaces = Sets.newHashSet();
     /** Set of over-limit templates that have been notified. */
-    private HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet();
+    private final HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet();
 
     /** Set of currently active {@link Notification} tags. */
-    private HashSet<String> mActiveNotifs = Sets.newHashSet();
+    private final HashSet<String> mActiveNotifs = Sets.newHashSet();
 
     /** Foreground at both UID and PID granularity. */
-    private SparseBooleanArray mUidForeground = new SparseBooleanArray();
-    private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
+    private final SparseBooleanArray mUidForeground = new SparseBooleanArray();
+    private final SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray<
             SparseBooleanArray>();
 
     private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<
@@ -328,12 +341,42 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             return;
         }
 
+        final PackageManager pm = mContext.getPackageManager();
+
         synchronized (mRulesLock) {
+            SystemConfig sysConfig = SystemConfig.getInstance();
+            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
+            for (int i=0; i<allowPower.size(); i++) {
+                String pkg = allowPower.valueAt(i);
+                try {
+                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
+                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        mPowerSaveWhitelistAppIds.put(UserHandle.getAppId(ai.uid), true);
+                    }
+                } catch (PackageManager.NameNotFoundException e) {
+                }
+            }
+
+            mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+            mPowerManagerInternal.registerLowPowerModeObserver(
+                    new PowerManagerInternal.LowPowerModeListener() {
+                @Override
+                public void onLowPowerModeChanged(boolean enabled) {
+                    synchronized (mRulesLock) {
+                        if (mRestrictPower != enabled) {
+                            mRestrictPower = enabled;
+                            updateRulesForGlobalChangeLocked(true);
+                        }
+                    }
+                }
+            });
+            mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
+
             // read policy from disk
             readPolicyLocked();
 
-            if (mRestrictBackground) {
-                updateRulesForRestrictBackgroundLocked();
+            if (mRestrictBackground || mRestrictPower) {
+                updateRulesForGlobalChangeLocked(true);
                 updateNotificationsLocked();
             }
         }
@@ -482,7 +525,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
 
             // Update global restrict for new user
             synchronized (mRulesLock) {
-                updateRulesForRestrictBackgroundLocked();
+                updateRulesForGlobalChangeLocked(true);
             }
         }
     };
@@ -633,7 +676,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
 
         // examine stats for each active policy
         final long currentTime = currentTimeMillis();
-        for (NetworkPolicy policy : mNetworkPolicy.values()) {
+        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+            final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
             // ignore policies that aren't relevant to user
             if (!isTemplateRelevant(policy.template)) continue;
             if (!policy.hasCycle()) continue;
@@ -912,7 +956,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         // completely, which is currently rare case.
 
         final long currentTime = currentTimeMillis();
-        for (NetworkPolicy policy : mNetworkPolicy.values()) {
+        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+            final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
             // shortcut when policy has no limit
             if (policy.limitBytes == LIMIT_DISABLED || !policy.hasCycle()) {
                 setNetworkTemplateEnabled(policy.template, true);
@@ -978,29 +1023,41 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             return;
         }
 
+        // If we are in restrict power mode, we want to treat all interfaces
+        // as metered, to restrict access to the network by uid.  However, we
+        // will not have a bandwidth limit.  Also only do this if restrict
+        // background data use is *not* enabled, since that takes precendence
+        // use over those networks can have a cost associated with it).
+        final boolean powerSave = mRestrictPower && !mRestrictBackground;
+
         // first, derive identity for all connected networks, which can be used
         // to match against templates.
-        final HashMap<NetworkIdentity, String> networks = Maps.newHashMap();
+        final ArrayMap<NetworkIdentity, String> networks = new ArrayMap();
+        final ArraySet<String> connIfaces = new ArraySet<String>();
         for (NetworkState state : states) {
             // stash identity and iface away for later use
             if (state.networkInfo.isConnected()) {
                 final String iface = state.linkProperties.getInterfaceName();
                 final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
                 networks.put(ident, iface);
+                if (powerSave) {
+                    connIfaces.add(iface);
+                }
             }
         }
 
         // build list of rules and ifaces to enforce them against
         mNetworkRules.clear();
         final ArrayList<String> ifaceList = Lists.newArrayList();
-        for (NetworkPolicy policy : mNetworkPolicy.values()) {
+        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+            final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
 
             // collect all active ifaces that match this template
             ifaceList.clear();
-            for (Map.Entry<NetworkIdentity, String> entry : networks.entrySet()) {
-                final NetworkIdentity ident = entry.getKey();
+            for (int j = networks.size()-1; j >= 0; j--) {
+                final NetworkIdentity ident = networks.keyAt(j);
                 if (policy.template.matches(ident)) {
-                    final String iface = entry.getValue();
+                    final String iface = networks.valueAt(j);
                     ifaceList.add(iface);
                 }
             }
@@ -1017,8 +1074,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         // apply each policy that we found ifaces for; compute remaining data
         // based on current cycle and historical stats, and push to kernel.
         final long currentTime = currentTimeMillis();
-        for (NetworkPolicy policy : mNetworkRules.keySet()) {
-            final String[] ifaces = mNetworkRules.get(policy);
+        for (int i = mNetworkRules.size()-1; i >= 0; i--) {
+            final NetworkPolicy policy = mNetworkRules.keyAt(i);
+            final String[] ifaces = mNetworkRules.valueAt(i);
 
             final long start;
             final long totalBytes;
@@ -1063,6 +1121,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                     removeInterfaceQuota(iface);
                     setInterfaceQuota(iface, quotaBytes);
                     newMeteredIfaces.add(iface);
+                    if (powerSave) {
+                        connIfaces.remove(iface);
+                    }
                 }
             }
 
@@ -1075,6 +1136,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             }
         }
 
+        for (int i = connIfaces.size()-1; i >= 0; i--) {
+            String iface = connIfaces.valueAt(i);
+            removeInterfaceQuota(iface);
+            setInterfaceQuota(iface, Long.MAX_VALUE);
+            newMeteredIfaces.add(iface);
+        }
+
         mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
 
         // remove quota on any trailing interfaces
@@ -1108,9 +1176,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
 
         // examine to see if any policy is defined for active mobile
         boolean mobileDefined = false;
-        for (NetworkPolicy policy : mNetworkPolicy.values()) {
-            if (policy.template.matches(probeIdent)) {
+        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+            if (mNetworkPolicy.valueAt(i).template.matches(probeIdent)) {
                 mobileDefined = true;
+                break;
             }
         }
 
@@ -1226,7 +1295,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                         final int policy = readIntAttribute(in, ATTR_POLICY);
 
                         if (UserHandle.isApp(uid)) {
-                            setUidPolicyUnchecked(uid, policy, false);
+                            setUidPolicyUncheckedLocked(uid, policy, false);
                         } else {
                             Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
                         }
@@ -1237,7 +1306,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                         // TODO: set for other users during upgrade
                         final int uid = UserHandle.getUid(UserHandle.USER_OWNER, appId);
                         if (UserHandle.isApp(uid)) {
-                            setUidPolicyUnchecked(uid, policy, false);
+                            setUidPolicyUncheckedLocked(uid, policy, false);
                         } else {
                             Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
                         }
@@ -1289,7 +1358,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
 
             // write all known network policies
-            for (NetworkPolicy policy : mNetworkPolicy.values()) {
+            for (int i = 0; i < mNetworkPolicy.size(); i++) {
+                final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
                 final NetworkTemplate template = policy.template;
 
                 out.startTag(null, TAG_NETWORK_POLICY);
@@ -1346,23 +1416,58 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             throw new IllegalArgumentException("cannot apply policy to UID " + uid);
         }
 
-        setUidPolicyUnchecked(uid, policy, true);
+        synchronized (mRulesLock) {
+            final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+            if (oldPolicy != policy) {
+                setUidPolicyUncheckedLocked(uid, policy, true);
+            }
+        }
     }
 
-    private void setUidPolicyUnchecked(int uid, int policy, boolean persist) {
-        final int oldPolicy;
+    @Override
+    public void addUidPolicy(int uid, int policy) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+        if (!UserHandle.isApp(uid)) {
+            throw new IllegalArgumentException("cannot apply policy to UID " + uid);
+        }
+
         synchronized (mRulesLock) {
-            oldPolicy = getUidPolicy(uid);
-            mUidPolicy.put(uid, policy);
+            final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+            policy |= oldPolicy;
+            if (oldPolicy != policy) {
+                setUidPolicyUncheckedLocked(uid, policy, true);
+            }
+        }
+    }
 
-            // uid policy changed, recompute rules and persist policy.
-            updateRulesForUidLocked(uid);
-            if (persist) {
-                writePolicyLocked();
+    @Override
+    public void removeUidPolicy(int uid, int policy) {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+        if (!UserHandle.isApp(uid)) {
+            throw new IllegalArgumentException("cannot apply policy to UID " + uid);
+        }
+
+        synchronized (mRulesLock) {
+            final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
+            policy = oldPolicy & ~policy;
+            if (oldPolicy != policy) {
+                setUidPolicyUncheckedLocked(uid, policy, true);
             }
         }
     }
 
+    private void setUidPolicyUncheckedLocked(int uid, int policy, boolean persist) {
+        mUidPolicy.put(uid, policy);
+
+        // uid policy changed, recompute rules and persist policy.
+        updateRulesForUidLocked(uid);
+        if (persist) {
+            writePolicyLocked();
+        }
+    }
+
     @Override
     public int getUidPolicy(int uid) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
@@ -1389,6 +1494,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         return uids;
     }
 
+    @Override
+    public int[] getPowerSaveAppIdWhitelist() {
+        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+        synchronized (mRulesLock) {
+            int size = mPowerSaveWhitelistAppIds.size();
+            int[] appids = new int[size];
+            for (int i = 0; i < size; i++) {
+                appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
+            }
+            return appids;
+        }
+    }
+
     /**
      * Remove any policies associated with given {@link UserHandle}, persisting
      * if any changes are made.
@@ -1515,7 +1634,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         maybeRefreshTrustedTime();
         synchronized (mRulesLock) {
             mRestrictBackground = restrictBackground;
-            updateRulesForRestrictBackgroundLocked();
+            updateRulesForGlobalChangeLocked(false);
             updateNotificationsLocked();
             writePolicyLocked();
         }
@@ -1534,7 +1653,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     }
 
     private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) {
-        for (NetworkPolicy policy : mNetworkPolicy.values()) {
+        for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+            NetworkPolicy policy = mNetworkPolicy.valueAt(i);
             if (policy.template.matches(ident)) {
                 return policy;
             }
@@ -1623,8 +1743,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
 
         synchronized (mRulesLock) {
             if (argSet.contains("--unsnooze")) {
-                for (NetworkPolicy policy : mNetworkPolicy.values()) {
-                    policy.clearSnooze();
+                for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
+                    mNetworkPolicy.valueAt(i).clearSnooze();
                 }
 
                 updateNetworkEnabledLocked();
@@ -1637,10 +1757,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             }
 
             fout.print("Restrict background: "); fout.println(mRestrictBackground);
+            fout.print("Restrict power: "); fout.println(mRestrictPower);
             fout.println("Network policies:");
             fout.increaseIndent();
-            for (NetworkPolicy policy : mNetworkPolicy.values()) {
-                fout.println(policy.toString());
+            for (int i = 0; i < mNetworkPolicy.size(); i++) {
+                fout.println(mNetworkPolicy.valueAt(i).toString());
             }
             fout.decreaseIndent();
 
@@ -1658,6 +1779,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             }
             fout.decreaseIndent();
 
+            size = mPowerSaveWhitelistAppIds.size();
+            if (size > 0) {
+                fout.println("Power save whitelist app ids:");
+                fout.increaseIndent();
+                for (int i = 0; i < size; i++) {
+                    fout.print("UID=");
+                    fout.print(mPowerSaveWhitelistAppIds.keyAt(i));
+                    fout.print(": ");
+                    fout.print(mPowerSaveWhitelistAppIds.valueAt(i));
+                    fout.println();
+                }
+                fout.decreaseIndent();
+            }
+
             final SparseBooleanArray knownUids = new SparseBooleanArray();
             collectKeys(mUidForeground, knownUids);
             collectKeys(mUidRules, knownUids);
@@ -1753,9 +1888,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     }
 
     /**
-     * Update rules that might be changed by {@link #mRestrictBackground} value.
+     * Update rules that might be changed by {@link #mRestrictBackground}
+     * or {@link #mRestrictPower} value.
      */
-    private void updateRulesForRestrictBackgroundLocked() {
+    private void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
         final PackageManager pm = mContext.getPackageManager();
         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
 
@@ -1774,6 +1910,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         // limit data usage for some internal system services
         updateRulesForUidLocked(android.os.Process.MEDIA_UID);
         updateRulesForUidLocked(android.os.Process.DRM_UID);
+
+        // If the set of restricted networks may have changed, re-evaluate those.
+        if (restrictedNetworksChanged) {
+            updateNetworkRulesLocked();
+        }
     }
 
     private static boolean isUidValidForRules(int uid) {
@@ -1797,10 +1938,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
             // uid in background, and policy says to block metered data
             uidRules = RULE_REJECT_METERED;
-        }
-        if (!uidForeground && mRestrictBackground) {
-            // uid in background, and global background disabled
-            uidRules = RULE_REJECT_METERED;
+        } else if (mRestrictBackground) {
+            if (!uidForeground) {
+                // uid in background, and global background disabled
+                uidRules = RULE_REJECT_METERED;
+            }
+        } else if (mRestrictPower) {
+            final boolean whitelisted = mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid));
+            if (!whitelisted && !uidForeground
+                    && (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) {
+                // uid is in background, restrict power use mode is on (so we want to
+                // restrict all background network access), and this uid is not on the
+                // white list of those allowed background access.
+                uidRules = RULE_REJECT_METERED;
+            }
         }
 
         // TODO: only dispatch when rules actually change
index cac27bc..cf32be9 100755 (executable)
@@ -36,6 +36,7 @@ import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.ArrayUtils.removeInt;
 
+import android.util.ArrayMap;
 import com.android.internal.R;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
@@ -50,6 +51,7 @@ import com.android.server.EventLogTags;
 import com.android.server.IntentResolver;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
 import com.android.server.pm.Settings.DatabaseVersion;
 import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -391,17 +393,20 @@ public class PackageManagerService extends IPackageManager.Stub {
     final Settings mSettings;
     boolean mRestoredSettings;
 
-    // Group-ids that are given to all packages as read from etc/permissions/*.xml.
-    int[] mGlobalGids;
+    // System configuration read by SystemConfig.
+    final int[] mGlobalGids;
+    final SparseArray<HashSet<String>> mSystemPermissions;
+    final HashMap<String, FeatureInfo> mAvailableFeatures;
 
-    // These are the built-in uid -> permission mappings that were read from the
-    // etc/permissions.xml file.
-    final SparseArray<HashSet<String>> mSystemPermissions =
-            new SparseArray<HashSet<String>>();
+    // If mac_permissions.xml was found for seinfo labeling.
+    boolean mFoundPolicyFile;
+
+    // If a recursive restorecon of /data/data/<pkg> is needed.
+    private boolean mShouldRestoreconData = SELinuxMMAC.shouldRestorecon();
 
-    static final class SharedLibraryEntry {
-        final String path;
-        final String apk;
+    public static final class SharedLibraryEntry {
+        public final String path;
+        public final String apk;
 
         SharedLibraryEntry(String _path, String _apk) {
             path = _path;
@@ -409,21 +414,9 @@ public class PackageManagerService extends IPackageManager.Stub {
         }
     }
 
-    // These are the built-in shared libraries that were read from the
-    // etc/permissions.xml file.
-    final HashMap<String, SharedLibraryEntry> mSharedLibraries
-            = new HashMap<String, SharedLibraryEntry>();
-
-    // These are the features this devices supports that were read from the
-    // etc/permissions.xml file.
-    final HashMap<String, FeatureInfo> mAvailableFeatures =
-            new HashMap<String, FeatureInfo>();
-
-    // If mac_permissions.xml was found for seinfo labeling.
-    boolean mFoundPolicyFile;
-
-    // If a recursive restorecon of /data/data/<pkg> is needed.
-    private boolean mShouldRestoreconData = SELinuxMMAC.shouldRestorecon();
+    // Currently known shared libraries.
+    final HashMap<String, SharedLibraryEntry> mSharedLibraries =
+            new HashMap<String, SharedLibraryEntry>();
 
     // All available activities, for your resolving pleasure.
     final ActivityIntentResolver mActivities =
@@ -1331,6 +1324,11 @@ public class PackageManagerService extends IPackageManager.Stub {
 
         getDefaultDisplayMetrics(context, mMetrics);
 
+        SystemConfig systemConfig = SystemConfig.getInstance();
+        mGlobalGids = systemConfig.getGlobalGids();
+        mSystemPermissions = systemConfig.getSystemPermissions();
+        mAvailableFeatures = systemConfig.getAvailableFeatures();
+
         synchronized (mInstallLock) {
         // writer
         synchronized (mPackages) {
@@ -1352,12 +1350,26 @@ public class PackageManagerService extends IPackageManager.Stub {
             sUserManager = new UserManagerService(context, this,
                     mInstallLock, mPackages);
 
-            // Read permissions and features from system
-            readPermissions(Environment.buildPath(
-                    Environment.getRootDirectory(), "etc", "permissions"), false);
-            // Only read features from OEM
-            readPermissions(Environment.buildPath(
-                    Environment.getOemDirectory(), "etc", "permissions"), true);
+            // Propagate permission configuration in to package manager.
+            ArrayMap<String, SystemConfig.PermissionEntry> permConfig
+                    = systemConfig.getPermissions();
+            for (int i=0; i<permConfig.size(); i++) {
+                SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
+                BasePermission bp = mSettings.mPermissions.get(perm.name);
+                if (bp == null) {
+                    bp = new BasePermission(perm.name, null, BasePermission.TYPE_BUILTIN);
+                    mSettings.mPermissions.put(perm.name, bp);
+                }
+                if (perm.gids != null) {
+                    bp.gids = appendInts(bp.gids, perm.gids);
+                }
+            }
+
+            ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
+            for (int i=0; i<libConfig.size(); i++) {
+                mSharedLibraries.put(libConfig.keyAt(i),
+                        new SharedLibraryEntry(libConfig.valueAt(i), null));
+            }
 
             mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
 
@@ -1822,198 +1834,6 @@ public class PackageManagerService extends IPackageManager.Stub {
         mSettings.removePackageLPw(ps.name);
     }
 
-    void readPermissions(File libraryDir, boolean onlyFeatures) {
-        // Read permissions from .../etc/permission directory.
-        if (!libraryDir.exists() || !libraryDir.isDirectory()) {
-            Slog.w(TAG, "No directory " + libraryDir + ", skipping");
-            return;
-        }
-        if (!libraryDir.canRead()) {
-            Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
-            return;
-        }
-
-        // Iterate over the files in the directory and scan .xml files
-        for (File f : libraryDir.listFiles()) {
-            // We'll read platform.xml last
-            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
-                continue;
-            }
-
-            if (!f.getPath().endsWith(".xml")) {
-                Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
-                continue;
-            }
-            if (!f.canRead()) {
-                Slog.w(TAG, "Permissions library file " + f + " cannot be read");
-                continue;
-            }
-
-            readPermissionsFromXml(f, onlyFeatures);
-        }
-
-        // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
-        final File permFile = new File(Environment.getRootDirectory(),
-                "etc/permissions/platform.xml");
-        readPermissionsFromXml(permFile, onlyFeatures);
-    }
-
-    private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
-        FileReader permReader = null;
-        try {
-            permReader = new FileReader(permFile);
-        } catch (FileNotFoundException e) {
-            Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
-            return;
-        }
-
-        try {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(permReader);
-
-            XmlUtils.beginDocument(parser, "permissions");
-
-            while (true) {
-                XmlUtils.nextElement(parser);
-                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
-                    break;
-                }
-
-                String name = parser.getName();
-                if ("group".equals(name) && !onlyFeatures) {
-                    String gidStr = parser.getAttributeValue(null, "gid");
-                    if (gidStr != null) {
-                        int gid = Process.getGidForName(gidStr);
-                        mGlobalGids = appendInt(mGlobalGids, gid);
-                    } else {
-                        Slog.w(TAG, "<group> without gid at "
-                                + parser.getPositionDescription());
-                    }
-
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                } else if ("permission".equals(name) && !onlyFeatures) {
-                    String perm = parser.getAttributeValue(null, "name");
-                    if (perm == null) {
-                        Slog.w(TAG, "<permission> without name at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    perm = perm.intern();
-                    readPermission(parser, perm);
-
-                } else if ("assign-permission".equals(name) && !onlyFeatures) {
-                    String perm = parser.getAttributeValue(null, "name");
-                    if (perm == null) {
-                        Slog.w(TAG, "<assign-permission> without name at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    String uidStr = parser.getAttributeValue(null, "uid");
-                    if (uidStr == null) {
-                        Slog.w(TAG, "<assign-permission> without uid at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    int uid = Process.getUidForName(uidStr);
-                    if (uid < 0) {
-                        Slog.w(TAG, "<assign-permission> with unknown uid \""
-                                + uidStr + "\" at "
-                                + parser.getPositionDescription());
-                        XmlUtils.skipCurrentTag(parser);
-                        continue;
-                    }
-                    perm = perm.intern();
-                    HashSet<String> perms = mSystemPermissions.get(uid);
-                    if (perms == null) {
-                        perms = new HashSet<String>();
-                        mSystemPermissions.put(uid, perms);
-                    }
-                    perms.add(perm);
-                    XmlUtils.skipCurrentTag(parser);
-
-                } else if ("library".equals(name) && !onlyFeatures) {
-                    String lname = parser.getAttributeValue(null, "name");
-                    String lfile = parser.getAttributeValue(null, "file");
-                    if (lname == null) {
-                        Slog.w(TAG, "<library> without name at "
-                                + parser.getPositionDescription());
-                    } else if (lfile == null) {
-                        Slog.w(TAG, "<library> without file at "
-                                + parser.getPositionDescription());
-                    } else {
-                        //Log.i(TAG, "Got library " + lname + " in " + lfile);
-                        mSharedLibraries.put(lname, new SharedLibraryEntry(lfile, null));
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
-                } else if ("feature".equals(name)) {
-                    String fname = parser.getAttributeValue(null, "name");
-                    if (fname == null) {
-                        Slog.w(TAG, "<feature> without name at "
-                                + parser.getPositionDescription());
-                    } else {
-                        //Log.i(TAG, "Got feature " + fname);
-                        FeatureInfo fi = new FeatureInfo();
-                        fi.name = fname;
-                        mAvailableFeatures.put(fname, fi);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
-                } else {
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-                }
-
-            }
-            permReader.close();
-        } catch (XmlPullParserException e) {
-            Slog.w(TAG, "Got execption parsing permissions.", e);
-        } catch (IOException e) {
-            Slog.w(TAG, "Got execption parsing permissions.", e);
-        }
-    }
-
-    void readPermission(XmlPullParser parser, String name)
-            throws IOException, XmlPullParserException {
-
-        name = name.intern();
-
-        BasePermission bp = mSettings.mPermissions.get(name);
-        if (bp == null) {
-            bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);
-            mSettings.mPermissions.put(name, bp);
-        }
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-               && (type != XmlPullParser.END_TAG
-                       || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG
-                    || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if ("group".equals(tagName)) {
-                String gidStr = parser.getAttributeValue(null, "gid");
-                if (gidStr != null) {
-                    int gid = Process.getGidForName(gidStr);
-                    bp.gids = appendInt(bp.gids, gid);
-                } else {
-                    Slog.w(TAG, "<group> without gid at "
-                            + parser.getPositionDescription());
-                }
-            }
-            XmlUtils.skipCurrentTag(parser);
-        }
-    }
-
     static int[] appendInts(int[] cur, int[] add) {
         if (add == null) return cur;
         if (cur == null) return add;
index 0d05c5f..52ca098 100644 (file)
@@ -404,6 +404,9 @@ public final class SystemServer {
         boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
 
         try {
+            Slog.i(TAG, "Reading configuration...");
+            SystemConfig.getInstance();
+
             Slog.i(TAG, "Scheduling Policy");
             ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());