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

Commit ac0ac49d authored by Danesh M's avatar Danesh M Committed by Łukasz Patron
Browse files

[2/3] NetworkManagement : Add ability to restrict app data/wifi usage

CYAN-3976
CRACKLING-834

Change-Id: Iaa0483d0ad64511184f0f31d93552a93fbab6dd0
parent 407237f4
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -54,6 +54,10 @@ public class NetworkPolicyManager {
    public static final int POLICY_REJECT_METERED_BACKGROUND = 0x1;
    /** Allow metered network use in the background even when in data usage save mode. */
    public static final int POLICY_ALLOW_METERED_BACKGROUND = 0x4;
    /** Reject application network traffic on cellular network */
    public static final int POLICY_REJECT_ON_DATA = 0x10000;
    /** Reject application network traffic on wifi network */
    public static final int POLICY_REJECT_ON_WLAN = 0x8000;

    /*
     * Rules defining whether an uid has access to a network given its type (metered / non-metered).
+6 −0
Original line number Diff line number Diff line
@@ -452,4 +452,10 @@ interface INetworkManagementService
    void setAllowOnlyVpnForUids(boolean enable, in UidRange[] uidRanges);

    boolean isNetworkRestricted(int uid);

    /**
     * Restrict UID from accessing data/wifi
     */
    void restrictAppOnData(int uid, boolean restrict);
    void restrictAppOnWlan(int uid, boolean restrict);
}
+113 −0
Original line number Diff line number Diff line
@@ -52,8 +52,11 @@ import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENAB

import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkManagementEventObserver;
@@ -61,6 +64,7 @@ import android.net.ITetheringStatsProvider;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkPolicyManager;
import android.net.NetworkStats;
@@ -90,6 +94,7 @@ import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -219,6 +224,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub

    private INetd mNetdService;

    private String mDataInterfaceName;
    private String mWlanInterfaceName;
    private BroadcastReceiver mPendingDataRestrictReceiver;

    private IBatteryStats mBatteryStats;

    private final Thread mThread;
@@ -252,6 +261,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub
    /** Set of UIDs whitelisted on metered networks. */
    @GuardedBy("mRulesLock")
    private SparseBooleanArray mUidAllowOnMetered = new SparseBooleanArray();
    /** Set of UIDs blacklisted on cellular networks. */
    @GuardedBy("mQuotaLock")
    final SparseBooleanArray mDataBlacklist = new SparseBooleanArray();
    /** Set of UIDs blacklisted on WiFi networks. */
    @GuardedBy("mQuotaLock")
    final SparseBooleanArray mWlanBlacklist = new SparseBooleanArray();
    /** Set of UIDs with cleartext penalties. */
    @GuardedBy("mQuotaLock")
    private SparseIntArray mUidCleartextPolicy = new SparseIntArray();
@@ -309,6 +324,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
    private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
            new RemoteCallbackList<>();
    private boolean mNetworkActive;
    private SparseBooleanArray mPendingRestrictOnData = new SparseBooleanArray();

    /**
     * Constructs a new NetworkManagementService instance
@@ -333,6 +349,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                FgThread.get().getLooper());
        mThread = new Thread(mConnector, NETD_TAG);

        mWlanInterfaceName = SystemProperties.get("wifi.interface");

        mDaemonHandler = new Handler(FgThread.get().getLooper());

        // Add ourself to the Watchdog monitors.
@@ -383,6 +401,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub
        } else {
            prepareNativeDaemon();
        }
        // Note: processPendingDataRestrictRequests() will unregister
        // mPendingDataRestrictReceiver once it has been able to determine
        // the cellular network interface name.
        mPendingDataRestrictReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                processPendingDataRestrictRequests();
           }
        };
        final IntentFilter filter = new IntentFilter();
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        mContext.registerReceiver(mPendingDataRestrictReceiver, filter);
    }

    private IBatteryStats getBatteryStats() {
@@ -1774,6 +1804,77 @@ public class NetworkManagementService extends INetworkManagementService.Stub
        }
    }

    @Override
    public void restrictAppOnData(int uid, boolean restrict) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
        // silently discard when control disabled
        if (!mBandwidthControlEnabled) return;

        initDataInterface();
        if (TextUtils.isEmpty(mDataInterfaceName)) {
            // We don't have an interface name since data is not active
            // yet, so queue up the request for when it comes up alive
            mPendingRestrictOnData.put(uid, restrict);
            return;
        }

        synchronized (mQuotaLock) {
            boolean oldValue = mDataBlacklist.get(uid, false);
            if (oldValue == restrict) {
                return;
            }
            mDataBlacklist.put(uid, restrict);
        }

        try {
            final String action = restrict ? "add" : "remove";
            mConnector.execute("bandwidth", action + "restrictappsondata",
                    mDataInterfaceName, uid);
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }

    @Override
    public void restrictAppOnWlan(int uid, boolean restrict) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
        // silently discard when control disabled
        if (!mBandwidthControlEnabled) return;

        synchronized (mQuotaLock) {
            boolean oldValue = mWlanBlacklist.get(uid, false);
            if (oldValue == restrict) {
                return;
            }
            mWlanBlacklist.put(uid, restrict);
        }

        try {
            final String action = restrict ? "add" : "remove";
            mConnector.execute("bandwidth", action + "restrictappsonwlan",
                    mWlanInterfaceName, uid);
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }

    private void processPendingDataRestrictRequests() {
        initDataInterface();
        if (TextUtils.isEmpty(mDataInterfaceName)) {
            return;
        }
        if (mPendingDataRestrictReceiver != null) {
            mContext.unregisterReceiver(mPendingDataRestrictReceiver);
            mPendingDataRestrictReceiver = null;
        }
        int count = mPendingRestrictOnData.size();
        for (int i = 0; i < count; i++) {
            restrictAppOnData(mPendingRestrictOnData.keyAt(i),
                    mPendingRestrictOnData.valueAt(i));
        }
        mPendingRestrictOnData.clear();
    }

    @Override
    public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
            throws ServiceSpecificException {
@@ -2756,6 +2857,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub
        }
    }

    private void initDataInterface() {
        if (!TextUtils.isEmpty(mDataInterfaceName)) {
            return;
        }
        ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
                Context.CONNECTIVITY_SERVICE);
        LinkProperties linkProperties = cm.getLinkProperties(ConnectivityManager.TYPE_MOBILE);
        if (linkProperties != null) {
            mDataInterfaceName = linkProperties.getInterfaceName();
        }
    }

    @VisibleForTesting
    class LocalService extends NetworkManagementInternal {
        @Override
+9 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_REJECT_ON_DATA;
import static android.net.NetworkPolicyManager.POLICY_REJECT_ON_WLAN;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
import static android.net.NetworkPolicyManager.RULE_NONE;
@@ -3589,6 +3591,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        final int oldRule = oldUidRules & MASK_METERED_NETWORKS;
        int newRule = RULE_NONE;

        try {
            mNetworkManager.restrictAppOnData(uid, (uidPolicy & POLICY_REJECT_ON_DATA) != 0);
            mNetworkManager.restrictAppOnWlan(uid, (uidPolicy & POLICY_REJECT_ON_WLAN) != 0);
        } catch (RemoteException e) {
            // ignored; service lives in system_server
        }

        // First step: define the new rule based on user restrictions and foreground state.
        if (isForeground) {
            if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) {