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

Commit 745952ea authored by Junyu Lai's avatar Junyu Lai Committed by android-build-merger
Browse files

Merge "Add new callback to inform blocking of network on specific uid."

am: f709e754

Change-Id: Ia99ee2fbefa67a7ee00d6fecce430ba6431945cd
parents 86ff3f4c f709e754
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -27167,6 +27167,7 @@ package android.net {
  public static class ConnectivityManager.NetworkCallback {
    ctor public ConnectivityManager.NetworkCallback();
    method public void onAvailable(android.net.Network);
    method public void onBlockedStatusChanged(android.net.Network, boolean);
    method public void onCapabilitiesChanged(android.net.Network, android.net.NetworkCapabilities);
    method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
    method public void onLosing(android.net.Network, int);
@@ -27438,16 +27439,16 @@ package android.net {
  public class NetworkInfo implements android.os.Parcelable {
    method public int describeContents();
    method public android.net.NetworkInfo.DetailedState getDetailedState();
    method public deprecated android.net.NetworkInfo.DetailedState getDetailedState();
    method public java.lang.String getExtraInfo();
    method public deprecated java.lang.String getReason();
    method public deprecated android.net.NetworkInfo.State getState();
    method public int getSubtype();
    method public java.lang.String getSubtypeName();
    method public deprecated int getSubtype();
    method public deprecated java.lang.String getSubtypeName();
    method public deprecated int getType();
    method public deprecated java.lang.String getTypeName();
    method public deprecated boolean isAvailable();
    method public boolean isConnected();
    method public deprecated boolean isConnected();
    method public deprecated boolean isConnectedOrConnecting();
    method public deprecated boolean isFailover();
    method public deprecated boolean isRoaming();
+21 −3
Original line number Diff line number Diff line
@@ -2816,10 +2816,11 @@ public class ConnectivityManager {
         * @param network The {@link Network} of the satisfying network.
         * @param networkCapabilities The {@link NetworkCapabilities} of the satisfying network.
         * @param linkProperties The {@link LinkProperties} of the satisfying network.
         * @param blocked Whether access to the {@link Network} is blocked due to system policy.
         * @hide
         */
        public void onAvailable(Network network, NetworkCapabilities networkCapabilities,
                LinkProperties linkProperties) {
                LinkProperties linkProperties, boolean blocked) {
            // Internally only this method is called when a new network is available, and
            // it calls the callback in the same way and order that older versions used
            // to call so as not to change the behavior.
@@ -2830,6 +2831,7 @@ public class ConnectivityManager {
            }
            onCapabilitiesChanged(network, networkCapabilities);
            onLinkPropertiesChanged(network, linkProperties);
            onBlockedStatusChanged(network, blocked);
        }

        /**
@@ -2837,7 +2839,8 @@ public class ConnectivityManager {
         * This callback may be called more than once if the {@link Network} that is
         * satisfying the request changes. This will always immediately be followed by a
         * call to {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} then by a
         * call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}.
         * call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}, and a call to
         * {@link #onBlockedStatusChanged(Network, boolean)}.
         *
         * @param network The {@link Network} of the satisfying network.
         */
@@ -2916,6 +2919,14 @@ public class ConnectivityManager {
         */
        public void onNetworkResumed(Network network) {}

        /**
         * Called when access to the specified network is blocked or unblocked.
         *
         * @param network The {@link Network} whose blocked status has changed.
         * @param blocked The blocked status of this {@link Network}.
         */
        public void onBlockedStatusChanged(Network network, boolean blocked) {}

        private NetworkRequest networkRequest;
    }

@@ -2962,6 +2973,8 @@ public class ConnectivityManager {
    public static final int CALLBACK_SUSPENDED           = BASE + 9;
    /** @hide */
    public static final int CALLBACK_RESUMED             = BASE + 10;
    /** @hide */
    public static final int CALLBACK_BLK_CHANGED         = BASE + 11;

    /** @hide */
    public static String getCallbackName(int whichCallback) {
@@ -2976,6 +2989,7 @@ public class ConnectivityManager {
            case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST";
            case CALLBACK_SUSPENDED:    return "CALLBACK_SUSPENDED";
            case CALLBACK_RESUMED:      return "CALLBACK_RESUMED";
            case CALLBACK_BLK_CHANGED:  return "CALLBACK_BLK_CHANGED";
            default:
                return Integer.toString(whichCallback);
        }
@@ -3022,7 +3036,7 @@ public class ConnectivityManager {
                case CALLBACK_AVAILABLE: {
                    NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
                    LinkProperties lp = getObject(message, LinkProperties.class);
                    callback.onAvailable(network, cap, lp);
                    callback.onAvailable(network, cap, lp, message.arg1 != 0);
                    break;
                }
                case CALLBACK_LOSING: {
@@ -3055,6 +3069,10 @@ public class ConnectivityManager {
                    callback.onNetworkResumed(network);
                    break;
                }
                case CALLBACK_BLK_CHANGED: {
                    boolean blocked = message.arg1 != 0;
                    callback.onBlockedStatusChanged(network, blocked);
                }
            }
        }

+10 −0
Original line number Diff line number Diff line
@@ -1589,4 +1589,14 @@ public final class NetworkCapabilities implements Parcelable {
        Preconditions.checkArgument(isValidCapability(capability),
                "NetworkCapability " + capability + "out of range");
    }

    /**
     * Check if this {@code NetworkCapability} instance is metered.
     *
     * @return {@code true} if {@code NET_CAPABILITY_NOT_METERED} is not set on this instance.
     * @hide
     */
    public boolean isMetered() {
        return !hasCapability(NET_CAPABILITY_NOT_METERED);
    }
}
+20 −0
Original line number Diff line number Diff line
@@ -202,7 +202,9 @@ public class NetworkInfo implements Parcelable {
     * Return a network-type-specific integer describing the subtype
     * of the network.
     * @return the network subtype
     * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead.
     */
    @Deprecated
    public int getSubtype() {
        synchronized (this) {
            return mSubtype;
@@ -243,7 +245,9 @@ public class NetworkInfo implements Parcelable {
    /**
     * Return a human-readable name describing the subtype of the network.
     * @return the name of the network subtype
     * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead.
     */
    @Deprecated
    public String getSubtypeName() {
        synchronized (this) {
            return mSubtypeName;
@@ -278,7 +282,15 @@ public class NetworkInfo implements Parcelable {
     * connections and pass data.
     * <p>Always call this before attempting to perform data transactions.
     * @return {@code true} if network connectivity exists, {@code false} otherwise.
     * @deprecated Apps should instead use the
     *             {@link android.net.ConnectivityManager.NetworkCallback} API to
     *             learn about connectivity changes. See
     *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
     *             {@link ConnectivityManager#registerNetworkCallback}. These will
     *             give a more accurate picture of the connectivity state of
     *             the device and let apps react more easily and quickly to changes.
     */
    @Deprecated
    public boolean isConnected() {
        synchronized (this) {
            return mState == State.CONNECTED;
@@ -411,7 +423,15 @@ public class NetworkInfo implements Parcelable {
    /**
     * Reports the current fine-grained state of the network.
     * @return the fine-grained state
     * @deprecated Apps should instead use the
     *             {@link android.net.ConnectivityManager.NetworkCallback} API to
     *             learn about connectivity changes. See
     *             {@link ConnectivityManager#registerDefaultNetworkCallback} and
     *             {@link ConnectivityManager#registerNetworkCallback}. These will
     *             give a more accurate picture of the connectivity state of
     *             the device and let apps react more easily and quickly to changes.
     */
    @Deprecated
    public DetailedState getDetailedState() {
        synchronized (this) {
            return mDetailedState;
+204 −10
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
@@ -189,6 +191,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -257,6 +260,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
    @GuardedBy("mVpns")
    private LockdownVpnTracker mLockdownTracker;

    /**
     * Stale copy of uid rules provided by NPMS. As long as they are accessed only in internal
     * handler thread, they don't need a lock.
     */
    private SparseIntArray mUidRules = new SparseIntArray();
    /** Flag indicating if background data is restricted. */
    private boolean mRestrictBackground;

    final private Context mContext;
    // 0 is full bad, 100 is full good
    private int mDefaultInetConditionPublished = 0;
@@ -419,6 +430,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
    // Handle private DNS validation status updates.
    private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38;

    /**
     * Used to handle onUidRulesChanged event from NetworkPolicyManagerService.
     */
    private static final int EVENT_UID_RULES_CHANGED = 39;

    /**
     * Used to handle onRestrictBackgroundChanged event from NetworkPolicyManagerService.
     */
    private static final int EVENT_DATA_SAVER_CHANGED = 40;

    private static String eventName(int what) {
        return sMagicDecoderRing.get(what, Integer.toString(what));
    }
@@ -780,6 +801,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
        mKeyStore = KeyStore.getInstance();
        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);

        // To ensure uid rules are synchronized with Network Policy, register for
        // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
        // reading existing policy from disk.
        try {
            mPolicyManager.registerListener(mPolicyListener);
        } catch (RemoteException e) {
@@ -1116,11 +1140,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
        if (ignoreBlocked) {
            return false;
        }
        // Networks are never blocked for system services
        // TODO: consider moving this check to NetworkPolicyManagerInternal.isUidNetworkingBlocked.
        if (isSystem(uid)) {
            return false;
        }
        synchronized (mVpns) {
            final Vpn vpn = mVpns.get(UserHandle.getUserId(uid));
            if (vpn != null && vpn.isBlockingUid(uid)) {
@@ -1150,6 +1169,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
        mNetworkInfoBlockingLogs.log(action + " " + uid);
    }

    private void maybeLogBlockedStatusChanged(NetworkRequestInfo nri, Network net,
            boolean blocked) {
        if (nri == null || net == null || !LOGD_BLOCKED_NETWORKINFO) {
            return;
        }
        String action = blocked ? "BLOCKED" : "UNBLOCKED";
        log(String.format("Blocked status changed to %s for %d(%d) on netId %d", blocked,
                nri.mUid, nri.request.requestId, net.netId));
        mNetworkInfoBlockingLogs.log(action + " " + nri.mUid);
    }

    /**
     * Apply any relevant filters to {@link NetworkState} for the given UID. For
     * example, this may mark the network as {@link DetailedState#BLOCKED} based
@@ -1651,10 +1681,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
    private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() {
        @Override
        public void onUidRulesChanged(int uid, int uidRules) {
            // TODO: notify UID when it has requested targeted updates
            mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_RULES_CHANGED, uid, uidRules));
        }
        @Override
        public void onRestrictBackgroundChanged(boolean restrictBackground) {
            // caller is NPMS, since we only register with them
            if (LOGD_BLOCKED_NETWORKINFO) {
                log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
            }
            mHandler.sendMessage(mHandler.obtainMessage(
                    EVENT_DATA_SAVER_CHANGED, restrictBackground ? 1 : 0, 0));

            // TODO: relocate this specific callback in Tethering.
            if (restrictBackground) {
                log("onRestrictBackgroundChanged(true): disabling tethering");
@@ -1663,6 +1700,50 @@ public class ConnectivityService extends IConnectivityManager.Stub
        }
    };

    void handleUidRulesChanged(int uid, int newRules) {
        // skip update when we've already applied rules
        final int oldRules = mUidRules.get(uid, RULE_NONE);
        if (oldRules == newRules) return;

        maybeNotifyNetworkBlockedForNewUidRules(uid, newRules);

        if (newRules == RULE_NONE) {
            mUidRules.delete(uid);
        } else {
            mUidRules.put(uid, newRules);
        }
    }

    void handleRestrictBackgroundChanged(boolean restrictBackground) {
        if (mRestrictBackground == restrictBackground) return;

        for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
            final boolean curMetered = nai.networkCapabilities.isMetered();
            maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground,
                    restrictBackground);
        }

        mRestrictBackground = restrictBackground;
    }

    private boolean isUidNetworkingWithVpnBlocked(int uid, int uidRules, boolean isNetworkMetered,
            boolean isBackgroundRestricted) {
        synchronized (mVpns) {
            final Vpn vpn = mVpns.get(UserHandle.getUserId(uid));
            // Because the return value of this function depends on the list of UIDs the
            // always-on VPN blocks when in lockdown mode, when the always-on VPN changes that
            // list all state depending on the return value of this function has to be recomputed.
            // TODO: add a trigger when the always-on VPN sets its blocked UIDs to reevaluate and
            // send the necessary onBlockedStatusChanged callbacks.
            if (vpn != null && vpn.isBlockingUid(uid)) {
                return true;
            }
        }

        return mPolicyManagerInternal.isUidNetworkingBlocked(uid, uidRules,
                isNetworkMetered, isBackgroundRestricted);
    }

    /**
     * Require that the caller is either in the same user or has appropriate permission to interact
     * across users.
@@ -2118,6 +2199,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
        pw.decreaseIndent();
        pw.println();

        pw.print("Restrict background: ");
        pw.println(mRestrictBackground);
        pw.println();

        pw.println("Status for known UIDs:");
        pw.increaseIndent();
        final int size = mUidRules.size();
        for (int i = 0; i < size; i++) {
            // Don't crash if the array is modified while dumping in bugreports.
            try {
                final int uid = mUidRules.keyAt(i);
                final int uidRules = mUidRules.get(uid, RULE_NONE);
                pw.println("UID=" + uid + " rules=" + uidRulesToString(uidRules));
            } catch (ArrayIndexOutOfBoundsException e) {
                pw.println("  ArrayIndexOutOfBoundsException");
            } catch (ConcurrentModificationException e) {
                pw.println("  ConcurrentModificationException");
            }
        }
        pw.println();
        pw.decreaseIndent();

        pw.println("Network Requests:");
        pw.increaseIndent();
        dumpNetworkRequests(pw);
@@ -3195,6 +3298,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
                    handlePrivateDnsValidationUpdate(
                            (PrivateDnsValidationUpdate) msg.obj);
                    break;
                case EVENT_UID_RULES_CHANGED:
                    handleUidRulesChanged(msg.arg1, msg.arg2);
                    break;
                case EVENT_DATA_SAVER_CHANGED:
                    handleRestrictBackgroundChanged(toBool(msg.arg1));
                    break;
            }
        }
    }
@@ -3783,6 +3892,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
    private void setLockdownTracker(LockdownVpnTracker tracker) {
        // Shutdown any existing tracker
        final LockdownVpnTracker existing = mLockdownTracker;
        // TODO: Add a trigger when the always-on VPN enable/disable to reevaluate and send the
        // necessary onBlockedStatusChanged callbacks.
        mLockdownTracker = null;
        if (existing != null) {
            existing.shutdown();
@@ -4893,12 +5004,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
        }

        // Report changes that are interesting for network statistics tracking.
        if (prevNc != null) {
            final boolean meteredChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_METERED) !=
                    newNc.hasCapability(NET_CAPABILITY_NOT_METERED);
            final boolean oldMetered = prevNc.isMetered();
            final boolean newMetered = newNc.isMetered();
            final boolean meteredChanged = oldMetered != newMetered;

            if (meteredChanged) {
                maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground,
                        mRestrictBackground);
            }

            final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
                    newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);

            // Report changes that are interesting for network statistics tracking.
            if (meteredChanged || roamingChanged) {
                notifyIfacesChangedForNetworkStats();
            }
@@ -5028,6 +5147,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
            case ConnectivityManager.CALLBACK_AVAILABLE: {
                putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));
                putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
                // For this notification, arg1 contains the blocked status.
                msg.arg1 = arg1;
                break;
            }
            case ConnectivityManager.CALLBACK_LOSING: {
@@ -5045,6 +5166,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
                putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
                break;
            }
            case ConnectivityManager.CALLBACK_BLK_CHANGED: {
                msg.arg1 = arg1;
                break;
            }
        }
        msg.what = notificationType;
        msg.setData(bundle);
@@ -5600,7 +5725,76 @@ public class ConnectivityService extends IConnectivityManager.Stub
            return;
        }

        callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, 0);
        final boolean metered = nai.networkCapabilities.isMetered();
        final boolean blocked = isUidNetworkingWithVpnBlocked(nri.mUid, mUidRules.get(nri.mUid),
                metered, mRestrictBackground);
        callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
    }

    /**
     * Notify of the blocked state apps with a registered callback matching a given NAI.
     *
     * Unlike other callbacks, blocked status is different between each individual uid. So for
     * any given nai, all requests need to be considered according to the uid who filed it.
     *
     * @param nai The target NetworkAgentInfo.
     * @param oldMetered True if the previous network capabilities is metered.
     * @param newRestrictBackground True if data saver is enabled.
     */
    private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered,
            boolean newMetered, boolean oldRestrictBackground, boolean newRestrictBackground) {

        for (int i = 0; i < nai.numNetworkRequests(); i++) {
            NetworkRequest nr = nai.requestAt(i);
            NetworkRequestInfo nri = mNetworkRequests.get(nr);
            final int uidRules = mUidRules.get(nri.mUid);
            final boolean oldBlocked, newBlocked;
            // mVpns lock needs to be hold here to ensure that the active VPN cannot be changed
            // between these two calls.
            synchronized (mVpns) {
                oldBlocked = isUidNetworkingWithVpnBlocked(nri.mUid, uidRules, oldMetered,
                        oldRestrictBackground);
                newBlocked = isUidNetworkingWithVpnBlocked(nri.mUid, uidRules, newMetered,
                        newRestrictBackground);
            }
            if (oldBlocked != newBlocked) {
                callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
                        encodeBool(newBlocked));
            }
        }
    }

    /**
     * Notify apps with a given UID of the new blocked state according to new uid rules.
     * @param uid The uid for which the rules changed.
     * @param newRules The new rules to apply.
     */
    private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) {
        for (final NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
            final boolean metered = nai.networkCapabilities.isMetered();
            final boolean oldBlocked, newBlocked;
            // TODO: Consider that doze mode or turn on/off battery saver would deliver lots of uid
            // rules changed event. And this function actually loop through all connected nai and
            // its requests. It seems that mVpns lock will be grabbed frequently in this case.
            // Reduce the number of locking or optimize the use of lock are likely needed in future.
            synchronized (mVpns) {
                oldBlocked = isUidNetworkingWithVpnBlocked(
                        uid, mUidRules.get(uid), metered, mRestrictBackground);
                newBlocked = isUidNetworkingWithVpnBlocked(
                        uid, newRules, metered, mRestrictBackground);
            }
            if (oldBlocked == newBlocked) {
                return;
            }
            final int arg = encodeBool(newBlocked);
            for (int i = 0; i < nai.numNetworkRequests(); i++) {
                NetworkRequest nr = nai.requestAt(i);
                NetworkRequestInfo nri = mNetworkRequests.get(nr);
                if (nri != null && nri.mUid == uid) {
                    callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg);
                }
            }
        }
    }

    private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
Loading