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

Commit 1a81a16a authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Notify policy listeners about metered ifaces."

parents 9c8e7358 fdfef57f
Loading
Loading
Loading
Loading
+11 −13
Original line number Original line Diff line number Diff line
@@ -225,6 +225,14 @@ public class DownloadManager {
     */
     */
    public final static int ERROR_FILE_ALREADY_EXISTS = 1009;
    public final static int ERROR_FILE_ALREADY_EXISTS = 1009;


    /**
     * Value of {@link #COLUMN_REASON} when the download has failed because of
     * {@link NetworkPolicyManager} controls on the requesting application.
     *
     * @hide
     */
    public final static int ERROR_BLOCKED = 1010;

    /**
    /**
     * Value of {@link #COLUMN_REASON} when the download is paused because some network error
     * Value of {@link #COLUMN_REASON} when the download is paused because some network error
     * occurred and the download manager is waiting before retrying the request.
     * occurred and the download manager is waiting before retrying the request.
@@ -248,14 +256,6 @@ public class DownloadManager {
     */
     */
    public final static int PAUSED_UNKNOWN = 4;
    public final static int PAUSED_UNKNOWN = 4;


    /**
     * Value of {@link #COLUMN_REASON} when the download has been paused because
     * of {@link NetworkPolicyManager} controls on the requesting application.
     *
     * @hide
     */
    public final static int PAUSED_BY_POLICY = 5;

    /**
    /**
     * Broadcast intent action sent by the download manager when a download completes.
     * Broadcast intent action sent by the download manager when a download completes.
     */
     */
@@ -804,7 +804,6 @@ public class DownloadManager {
                    parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_TO_RETRY));
                    parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_TO_RETRY));
                    parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_FOR_NETWORK));
                    parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_FOR_NETWORK));
                    parts.add(statusClause("=", Downloads.Impl.STATUS_QUEUED_FOR_WIFI));
                    parts.add(statusClause("=", Downloads.Impl.STATUS_QUEUED_FOR_WIFI));
                    parts.add(statusClause("=", Downloads.Impl.STATUS_PAUSED_BY_POLICY));
                }
                }
                if ((mStatusFlags & STATUS_SUCCESSFUL) != 0) {
                if ((mStatusFlags & STATUS_SUCCESSFUL) != 0) {
                    parts.add(statusClause("=", Downloads.Impl.STATUS_SUCCESS));
                    parts.add(statusClause("=", Downloads.Impl.STATUS_SUCCESS));
@@ -1275,9 +1274,6 @@ public class DownloadManager {
                case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
                case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
                    return PAUSED_QUEUED_FOR_WIFI;
                    return PAUSED_QUEUED_FOR_WIFI;


                case Downloads.Impl.STATUS_PAUSED_BY_POLICY:
                    return PAUSED_BY_POLICY;

                default:
                default:
                    return PAUSED_UNKNOWN;
                    return PAUSED_UNKNOWN;
            }
            }
@@ -1316,6 +1312,9 @@ public class DownloadManager {
                case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR:
                case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR:
                    return ERROR_FILE_ALREADY_EXISTS;
                    return ERROR_FILE_ALREADY_EXISTS;


                case Downloads.Impl.STATUS_BLOCKED:
                    return ERROR_BLOCKED;

                default:
                default:
                    return ERROR_UNKNOWN;
                    return ERROR_UNKNOWN;
            }
            }
@@ -1333,7 +1332,6 @@ public class DownloadManager {
                case Downloads.Impl.STATUS_WAITING_TO_RETRY:
                case Downloads.Impl.STATUS_WAITING_TO_RETRY:
                case Downloads.Impl.STATUS_WAITING_FOR_NETWORK:
                case Downloads.Impl.STATUS_WAITING_FOR_NETWORK:
                case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
                case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
                case Downloads.Impl.STATUS_PAUSED_BY_POLICY:
                    return STATUS_PAUSED;
                    return STATUS_PAUSED;


                case Downloads.Impl.STATUS_SUCCESS:
                case Downloads.Impl.STATUS_SUCCESS:
+2 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package android.net;
/** {@hide} */
/** {@hide} */
oneway interface INetworkPolicyListener {
oneway interface INetworkPolicyListener {


    void onRulesChanged(int uid, int uidRules);
    void onUidRulesChanged(int uid, int uidRules);
    void onMeteredIfacesChanged(in String[] meteredIfaces);


}
}
+9 −9
Original line number Original line Diff line number Diff line
@@ -34,13 +34,13 @@ public class NetworkPolicyManager {


    /** No specific network policy, use system default. */
    /** No specific network policy, use system default. */
    public static final int POLICY_NONE = 0x0;
    public static final int POLICY_NONE = 0x0;
    /** Reject network usage on paid networks when application in background. */
    /** Reject network usage on metered networks when application in background. */
    public static final int POLICY_REJECT_PAID_BACKGROUND = 0x1;
    public static final int POLICY_REJECT_METERED_BACKGROUND = 0x1;


    /** All network traffic should be allowed. */
    /** All network traffic should be allowed. */
    public static final int RULE_ALLOW_ALL = 0x0;
    public static final int RULE_ALLOW_ALL = 0x0;
    /** Reject traffic on paid networks. */
    /** Reject traffic on metered networks. */
    public static final int RULE_REJECT_PAID = 0x1;
    public static final int RULE_REJECT_METERED = 0x1;


    /**
    /**
     * {@link Intent} action launched when user selects {@link NetworkPolicy}
     * {@link Intent} action launched when user selects {@link NetworkPolicy}
@@ -98,7 +98,7 @@ public class NetworkPolicyManager {
     * Set policy flags for specific UID.
     * Set policy flags for specific UID.
     *
     *
     * @param policy {@link #POLICY_NONE} or combination of flags like
     * @param policy {@link #POLICY_NONE} or combination of flags like
     *            {@link #POLICY_REJECT_PAID_BACKGROUND}.
     *            {@link #POLICY_REJECT_METERED_BACKGROUND}.
     */
     */
    public void setUidPolicy(int uid, int policy) {
    public void setUidPolicy(int uid, int policy) {
        try {
        try {
@@ -217,8 +217,8 @@ public class NetworkPolicyManager {
    /** {@hide} */
    /** {@hide} */
    public static void dumpPolicy(PrintWriter fout, int policy) {
    public static void dumpPolicy(PrintWriter fout, int policy) {
        fout.write("[");
        fout.write("[");
        if ((policy & POLICY_REJECT_PAID_BACKGROUND) != 0) {
        if ((policy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
            fout.write("REJECT_PAID_BACKGROUND");
            fout.write("REJECT_METERED_BACKGROUND");
        }
        }
        fout.write("]");
        fout.write("]");
    }
    }
@@ -226,8 +226,8 @@ public class NetworkPolicyManager {
    /** {@hide} */
    /** {@hide} */
    public static void dumpRules(PrintWriter fout, int rules) {
    public static void dumpRules(PrintWriter fout, int rules) {
        fout.write("[");
        fout.write("[");
        if ((rules & RULE_REJECT_PAID) != 0) {
        if ((rules & RULE_REJECT_METERED) != 0) {
            fout.write("REJECT_PAID");
            fout.write("REJECT_METERED");
        }
        }
        fout.write("]");
        fout.write("]");
    }
    }
+8 −8
Original line number Original line Diff line number Diff line
@@ -547,14 +547,6 @@ public final class Downloads {
            return (status >= 200 && status < 300) || (status >= 400 && status < 600);
            return (status >= 200 && status < 300) || (status >= 400 && status < 600);
        }
        }


        /**
         * This download has been paused because requesting application has been
         * blocked by {@link NetworkPolicyManager}.
         *
         * @hide
         */
        public static final int STATUS_PAUSED_BY_POLICY = 189;

        /**
        /**
         * This download hasn't stated yet
         * This download hasn't stated yet
         */
         */
@@ -703,6 +695,14 @@ public final class Downloads {
         */
         */
        public static final int STATUS_TOO_MANY_REDIRECTS = 497;
        public static final int STATUS_TOO_MANY_REDIRECTS = 497;


        /**
         * This download has failed because requesting application has been
         * blocked by {@link NetworkPolicyManager}.
         *
         * @hide
         */
        public static final int STATUS_BLOCKED = 498;

        /**
        /**
         * This download is visible but only shows in the notifications
         * This download is visible but only shows in the notifications
         * while it's in progress.
         * while it's in progress.
+55 −26
Original line number Original line Diff line number Diff line
@@ -19,7 +19,7 @@ package com.android.server;
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_PAID;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;


import android.bluetooth.BluetoothTetheringDataTracker;
import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.ContentResolver;
import android.content.ContentResolver;
@@ -71,6 +71,7 @@ import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
import com.android.server.connectivity.Vpn;


import com.google.android.collect.Lists;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.IOException;
@@ -78,8 +79,10 @@ import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicBoolean;


@@ -108,8 +111,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {


    private Vpn mVpn;
    private Vpn mVpn;


    /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
    private Object mRulesLock = new Object();
    /** Currently active network rules by UID. */
    /** Currently active network rules by UID. */
    private SparseIntArray mUidRules = new SparseIntArray();
    private SparseIntArray mUidRules = new SparseIntArray();
    /** Set of ifaces that are costly. */
    private HashSet<String> mMeteredIfaces = Sets.newHashSet();


    /**
    /**
     * Sometimes we want to refer to the individual network state
     * Sometimes we want to refer to the individual network state
@@ -570,31 +577,35 @@ public class ConnectivityService extends IConnectivityManager.Stub {
    }
    }


    /**
    /**
     * Check if UID is blocked from using the given {@link NetworkInfo}.
     * Check if UID should be blocked from using the network represented by the
     * given {@link NetworkStateTracker}.
     */
     */
    private boolean isNetworkBlocked(NetworkInfo info, int uid) {
    private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) {
        synchronized (mUidRules) {
        final String iface = tracker.getLinkProperties().getInterfaceName();
            // TODO: expand definition of "paid" network to cover tethered or

            // paid hotspot use cases.
        final boolean networkCostly;
            final boolean networkIsPaid = info.getType() != ConnectivityManager.TYPE_WIFI;
        final int uidRules;
            final int uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
        synchronized (mRulesLock) {

            networkCostly = mMeteredIfaces.contains(iface);
            if (networkIsPaid && (uidRules & RULE_REJECT_PAID) != 0) {
            uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
        }

        if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
            return true;
            return true;
        }
        }


        // no restrictive rules; network is visible
        // no restrictive rules; network is visible
        return false;
        return false;
    }
    }
    }


    /**
    /**
     * Return a filtered version of the given {@link NetworkInfo}, potentially
     * Return a filtered {@link NetworkInfo}, potentially marked
     * marked {@link DetailedState#BLOCKED} based on
     * {@link DetailedState#BLOCKED} based on
     * {@link #isNetworkBlocked(NetworkInfo, int)}.
     * {@link #isNetworkBlocked(NetworkStateTracker, int)}.
     */
     */
    private NetworkInfo filterNetworkInfo(NetworkInfo info, int uid) {
    private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) {
        if (isNetworkBlocked(info, uid)) {
        NetworkInfo info = tracker.getNetworkInfo();
        if (isNetworkBlocked(tracker, uid)) {
            // network is blocked; clone and override state
            // network is blocked; clone and override state
            info = new NetworkInfo(info);
            info = new NetworkInfo(info);
            info.setDetailedState(DetailedState.BLOCKED, null, null);
            info.setDetailedState(DetailedState.BLOCKED, null, null);
@@ -634,7 +645,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        if (isNetworkTypeValid(networkType)) {
        if (isNetworkTypeValid(networkType)) {
            final NetworkStateTracker tracker = mNetTrackers[networkType];
            final NetworkStateTracker tracker = mNetTrackers[networkType];
            if (tracker != null) {
            if (tracker != null) {
                info = filterNetworkInfo(tracker.getNetworkInfo(), uid);
                info = getFilteredNetworkInfo(tracker, uid);
            }
            }
        }
        }
        return info;
        return info;
@@ -645,10 +656,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        enforceAccessPermission();
        enforceAccessPermission();
        final int uid = Binder.getCallingUid();
        final int uid = Binder.getCallingUid();
        final ArrayList<NetworkInfo> result = Lists.newArrayList();
        final ArrayList<NetworkInfo> result = Lists.newArrayList();
        synchronized (mUidRules) {
        synchronized (mRulesLock) {
            for (NetworkStateTracker tracker : mNetTrackers) {
            for (NetworkStateTracker tracker : mNetTrackers) {
                if (tracker != null) {
                if (tracker != null) {
                    result.add(filterNetworkInfo(tracker.getNetworkInfo(), uid));
                    result.add(getFilteredNetworkInfo(tracker, uid));
                }
                }
            }
            }
        }
        }
@@ -685,10 +696,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        enforceAccessPermission();
        enforceAccessPermission();
        final int uid = Binder.getCallingUid();
        final int uid = Binder.getCallingUid();
        final ArrayList<NetworkState> result = Lists.newArrayList();
        final ArrayList<NetworkState> result = Lists.newArrayList();
        synchronized (mUidRules) {
        synchronized (mRulesLock) {
            for (NetworkStateTracker tracker : mNetTrackers) {
            for (NetworkStateTracker tracker : mNetTrackers) {
                if (tracker != null) {
                if (tracker != null) {
                    final NetworkInfo info = filterNetworkInfo(tracker.getNetworkInfo(), uid);
                    final NetworkInfo info = getFilteredNetworkInfo(tracker, uid);
                    result.add(new NetworkState(
                    result.add(new NetworkState(
                            info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
                            info, tracker.getLinkProperties(), tracker.getLinkCapabilities()));
                }
                }
@@ -1139,15 +1150,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {


    private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
    private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
        @Override
        @Override
        public void onRulesChanged(int uid, int uidRules) {
        public void onUidRulesChanged(int uid, int uidRules) {
            // only someone like NPMS should only be calling us
            // only someone like NPMS should only be calling us
            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);


            if (LOGD_RULES) {
            if (LOGD_RULES) {
                Slog.d(TAG, "onRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
                Slog.d(TAG, "onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
            }
            }


            synchronized (mUidRules) {
            synchronized (mRulesLock) {
                // skip update when we've already applied rules
                // skip update when we've already applied rules
                final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
                final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL);
                if (oldRules == uidRules) return;
                if (oldRules == uidRules) return;
@@ -1158,6 +1169,24 @@ public class ConnectivityService extends IConnectivityManager.Stub {
            // TODO: dispatch into NMS to push rules towards kernel module
            // TODO: dispatch into NMS to push rules towards kernel module
            // TODO: notify UID when it has requested targeted updates
            // TODO: notify UID when it has requested targeted updates
        }
        }

        @Override
        public void onMeteredIfacesChanged(String[] meteredIfaces) {
            // only someone like NPMS should only be calling us
            mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);

            if (LOGD_RULES) {
                Slog.d(TAG,
                        "onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
            }

            synchronized (mRulesLock) {
                mMeteredIfaces.clear();
                for (String iface : meteredIfaces) {
                    mMeteredIfaces.add(iface);
                }
            }
        }
    };
    };


    /**
    /**
Loading