Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b85a637e authored by Felipe Leme's avatar Felipe Leme
Browse files

Added API to whitelist apps for background restriction.

The new APIs are:

    void addRestrictBackgroundWhitelistedUid(int uid);
    void removeRestrictBackgroundWhitelistedUid(int uid);
    int[] getRestrictBackgroundWhitelistedUids();

The whitelist is persisted in the same XML used for the other policies,
using the new 'whitelist and 'restrict-background' tags. Examples:

3 whitelisted apps:

<whitelist>
  <restrict-background uid="10001" />
  <restrict-background uid="10009" />
  <restrict-background uid="10086" />
</whitelist>

No whitelisted app:
<whitelist />

BUG: 26451391

Change-Id: I01b114c346fd8abc05433ad43d010379384f8c2b
parent 659133c7
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -52,6 +52,11 @@ interface INetworkPolicyManager {
    void setRestrictBackground(boolean restrictBackground);
    boolean getRestrictBackground();

    /** Control which applications can be exempt from background data restrictions */
    void addRestrictBackgroundWhitelistedUid(int uid);
    void removeRestrictBackgroundWhitelistedUid(int uid);
    int[] getRestrictBackgroundWhitelistedUids();

    void setDeviceIdleMode(boolean enabled);

    NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state);
+121 −3
Original line number Diff line number Diff line
@@ -75,6 +75,7 @@ import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.START_TAG;

import android.Manifest;
@@ -153,6 +154,7 @@ import libcore.io.IoUtils;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -213,6 +215,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private static final String TAG_NETWORK_POLICY = "network-policy";
    private static final String TAG_UID_POLICY = "uid-policy";
    private static final String TAG_APP_POLICY = "app-policy";
    private static final String TAG_WHITELIST = "whitelist";
    private static final String TAG_RESTRICT_BACKGROUND = "restrict-background";

    private static final String ATTR_VERSION = "version";
    private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground";
@@ -304,6 +308,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

    private final SparseBooleanArray mPowerSaveTempWhitelistAppIds = new SparseBooleanArray();

    /**
     * UIDs that have been white-listed to avoid restricted background.
     */
    private final SparseBooleanArray mRestrictBackgroundWhitelistUids = new SparseBooleanArray();

    /** Set of ifaces that are metered. */
    private ArraySet<String> mMeteredIfaces = new ArraySet<>();
    /** Set of over-limit templates that have been notified. */
@@ -324,6 +333,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

    private final AppOpsManager mAppOps;

    private final MyPackageMonitor mPackageMonitor;

    // TODO: keep whitelist of system-critical services that should never have
    // rules enforced, such as system, phone, and radio UIDs.

@@ -363,6 +374,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));

        mAppOps = context.getSystemService(AppOpsManager.class);

        mPackageMonitor = new MyPackageMonitor();
    }

    public void bindConnectivityManager(IConnectivityManager connManager) {
@@ -431,6 +444,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

        mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);

        mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);

        synchronized (mRulesLock) {
            updatePowerSaveWhitelistLocked();
            mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
@@ -1127,7 +1142,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        // 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
        // background data use is *not* enabled, since that takes precedence
        // use over those networks can have a cost associated with it).
        final boolean powerSave = mRestrictPower && !mRestrictBackground;

@@ -1339,6 +1354,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

            int type;
            int version = VERSION_INIT;
            boolean insideWhitelist = false;
            while ((type = in.next()) != END_DOCUMENT) {
                final String tag = in.getName();
                if (type == START_TAG) {
@@ -1431,7 +1447,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                        } else {
                            Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
                        }
                    } else if (TAG_WHITELIST.equals(tag)) {
                        insideWhitelist = true;
                    } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) {
                        final int uid = readIntAttribute(in, ATTR_UID);
                        mRestrictBackgroundWhitelistUids.put(uid, true);
                    }
                } else if (type == END_TAG) {
                    if (TAG_WHITELIST.equals(tag)) {
                        insideWhitelist = false;
                    }

                }
            }

@@ -1519,6 +1545,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            }

            out.endTag(null, TAG_POLICY_LIST);

            // write all whitelists
            out.startTag(null, TAG_WHITELIST);

            // restrict background whitelist
            final int size = mRestrictBackgroundWhitelistUids.size();
            for (int i = 0; i < size; i++) {
                final int uid = mRestrictBackgroundWhitelistUids.keyAt(i);
                out.startTag(null, TAG_RESTRICT_BACKGROUND);
                writeIntAttribute(out, ATTR_UID, uid);
                out.endTag(null, TAG_RESTRICT_BACKGROUND);
            }

            out.endTag(null, TAG_WHITELIST);

            out.endDocument();

            mPolicyFile.finishWrite(fos);
@@ -1788,6 +1829,49 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                .sendToTarget();
    }

    @Override
    public void addRestrictBackgroundWhitelistedUid(int uid) {
        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
        Slog.i(TAG, "adding uid " + uid + " to restrict background whitelist");
        synchronized (mRulesLock) {
            mRestrictBackgroundWhitelistUids.append(uid, true);
            writePolicyLocked();
            // TODO: call other update methods like updateNetworkRulesLocked?
        }
    }

    @Override
    public void removeRestrictBackgroundWhitelistedUid(int uid) {
        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
        Slog.i(TAG, "removing uid " + uid + " from restrict background whitelist");
        synchronized (mRulesLock) {
            removeRestrictBackgroundWhitelistedUidLocked(uid);
        }
    }

    private void removeRestrictBackgroundWhitelistedUidLocked(int uid) {
        mRestrictBackgroundWhitelistUids.delete(uid);
        writePolicyLocked();
        // TODO: call other update methods like updateNetworkRulesLocked?
    }

    @Override
    public int[] getRestrictBackgroundWhitelistedUids() {
        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
        synchronized (mRulesLock) {
            final int size = mRestrictBackgroundWhitelistUids.size();
            final int[] whitelist = new int[size];
            for (int i = 0; i < size; i++) {
                whitelist[i] = mRestrictBackgroundWhitelistUids.keyAt(i);
            }
            if (LOGV) {
                Slog.v(TAG, "getRestrictBackgroundWhitelistedUids(): "
                        + mRestrictBackgroundWhitelistUids);
            }
            return whitelist;
        }
    }

    @Override
    public boolean getRestrictBackground() {
        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
@@ -1978,6 +2062,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                fout.decreaseIndent();
            }

            size = mRestrictBackgroundWhitelistUids.size();
            if (size > 0) {
                fout.println("Restrict background whitelist uids:");
                fout.increaseIndent();
                for (int i = 0; i < size; i++) {
                    fout.print("UID=");
                    fout.print(mRestrictBackgroundWhitelistUids.keyAt(i));
                    fout.println();
                }
                fout.decreaseIndent();
            }

            final SparseBooleanArray knownUids = new SparseBooleanArray();
            collectKeys(mUidState, knownUids);
            collectKeys(mUidRules, knownUids);
@@ -2279,9 +2375,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            uidRules = RULE_REJECT_METERED;
        } else if (mRestrictBackground) {
            if (!uidForeground) {
                // uid in background, and global background disabled
                // uid in background, global background disabled, and this uid is not on the white
                // list of those allowed background access while global background is disabled
                if (!mRestrictBackgroundWhitelistUids.get(uid)) {
                    uidRules = RULE_REJECT_METERED;
                }
            }
        } else if (mRestrictPower) {
            final boolean whitelisted = mPowerSaveWhitelistExceptIdleAppIds.get(appId)
                    || mPowerSaveTempWhitelistAppIds.get(appId);
@@ -2642,4 +2741,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            }
        }
    }

    private class MyPackageMonitor extends PackageMonitor {

        @Override
        public void onPackageRemoved(String packageName, int uid) {
            if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
            synchronized (mRulesLock) {
                removeRestrictBackgroundWhitelistedUidLocked(uid);
            }
        }

        @Override
        public void onPackageRemovedAllUsers(String packageName, int uid) {
            if (LOGV) Slog.v(TAG, "onPackageRemovedAllUsers: " + packageName + " ->" + uid);
            synchronized (mRulesLock) {
                removeRestrictBackgroundWhitelistedUidLocked(uid);
            }
        }
    }
}