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

Commit 2108a924 authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by Gerrit Code Review
Browse files

Merge changes from topic "blocked-reasons-callback-tests"

* changes:
  Add unit tests for onBlockedStatusChanged(Network, int).
  Add onBlockedStatusChanged(Network, int) to NetworkCallback.
  Add MOBILE_DATA_PREFERRED_APPS setting
  Add PRIVATE_DNS_MODE setting setter
  Expose ConnectivitySettingsManager as module-lib API
parents 7236cf6d 8cbf5883
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.net;

import static android.app.ActivityManager.procStateToString;
import static android.content.pm.PackageManager.GET_SIGNATURES;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;

import android.annotation.IntDef;
@@ -204,9 +205,6 @@ public class NetworkPolicyManager {
    })
    public @interface SubscriptionOverrideMask {}

    /** @hide */
    public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;

    /**
     * Flag to indicate that app is not exempt from any network restrictions.
     *
+53 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ package android.net {
    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
    method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
    method public static void setPrivateDnsMode(@NonNull android.content.Context, @NonNull String);
    method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
@@ -27,10 +28,12 @@ package android.net {
    method public void systemReady();
    field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000
    field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000
    field public static final int BLOCKED_METERED_REASON_MASK = -65536; // 0xffff0000
    field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000
    field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4
    field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
    field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
    field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
    field public static final int BLOCKED_REASON_NONE = 0; // 0x0
    field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
    field public static final String PRIVATE_DNS_MODE_OFF = "off";
@@ -40,6 +43,56 @@ package android.net {
    field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
  }

  public static class ConnectivityManager.NetworkCallback {
    method public void onBlockedStatusChanged(@NonNull android.net.Network, int);
  }

  public class ConnectivitySettingsManager {
    method public static void clearGlobalProxy(@NonNull android.content.Context);
    method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context);
    method public static int getCaptivePortalMode(@NonNull android.content.Context, int);
    method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
    method @NonNull public static android.util.Range<java.lang.Integer> getDnsResolverSampleRanges(@NonNull android.content.Context);
    method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
    method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int);
    method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context);
    method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
    method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
    method @Nullable public static String getMobileDataPreferredApps(@NonNull android.content.Context);
    method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
    method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context);
    method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int);
    method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
    method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
    method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
    method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
    method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
    method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
    method public static void setCaptivePortalMode(@NonNull android.content.Context, int);
    method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
    method public static void setDnsResolverSampleRanges(@NonNull android.content.Context, @NonNull android.util.Range<java.lang.Integer>);
    method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
    method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int);
    method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo);
    method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
    method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
    method public static void setMobileDataPreferredApps(@NonNull android.content.Context, @Nullable String);
    method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
    method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
    method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
    method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
    method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull String);
    method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
    method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
    method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
    field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
    field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
    field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1
    field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2
    field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0
    field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1
  }

  public final class NetworkAgentConfig implements android.os.Parcelable {
    method @Nullable public String getSubscriberId();
    method public boolean isBypassableVpn();
+83 −6
Original line number Diff line number Diff line
@@ -38,7 +38,9 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -871,6 +873,17 @@ public class ConnectivityManager {
    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    public static final int BLOCKED_REASON_RESTRICTED_MODE = 1 << 3;

    /**
     * Flag to indicate that an app is blocked because it is subject to an always-on VPN but the VPN
     * is not currently connected.
     *
     * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean)
     *
     * @hide
     */
    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    public static final int BLOCKED_REASON_LOCKDOWN_VPN = 1 << 4;

    /**
     * Flag to indicate that an app is subject to Data saver restrictions that would
     * result in its metered network access being blocked.
@@ -914,6 +927,14 @@ public class ConnectivityManager {
    })
    public @interface BlockedReason {}

    /**
     * Set of blocked reasons that are only applicable on metered networks.
     *
     * @hide
     */
    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
    private final IConnectivityManager mService;

@@ -3442,12 +3463,30 @@ public class ConnectivityManager {
         * @param blocked Whether access to the {@link Network} is blocked due to system policy.
         * @hide
         */
        public void onAvailable(@NonNull Network network,
        public final void onAvailable(@NonNull Network network,
                @NonNull NetworkCapabilities networkCapabilities,
                @NonNull LinkProperties linkProperties, boolean blocked) {
                @NonNull LinkProperties linkProperties, @BlockedReason int 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.
            onAvailable(network, networkCapabilities, linkProperties, blocked != 0);
            onBlockedStatusChanged(network, blocked);
        }

        /**
         * Legacy variant of onAvailable that takes a boolean blocked reason.
         *
         * This method has never been public API, but it's not final, so there may be apps that
         * implemented it and rely on it being called. Do our best not to break them.
         * Note: such apps will also get a second call to onBlockedStatusChanged immediately after
         * this method is called. There does not seem to be a way to avoid this.
         * TODO: add a compat check to move apps off this method, and eventually stop calling it.
         *
         * @hide
         */
        public void onAvailable(@NonNull Network network,
                @NonNull NetworkCapabilities networkCapabilities,
                @NonNull LinkProperties linkProperties, boolean blocked) {
            onAvailable(network);
            if (!networkCapabilities.hasCapability(
                    NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
@@ -3455,7 +3494,7 @@ public class ConnectivityManager {
            }
            onCapabilitiesChanged(network, networkCapabilities);
            onLinkPropertiesChanged(network, linkProperties);
            onBlockedStatusChanged(network, blocked);
            // No call to onBlockedStatusChanged here. That is done by the caller.
        }

        /**
@@ -3619,6 +3658,26 @@ public class ConnectivityManager {
         */
        public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {}

        /**
         * Called when access to the specified network is blocked or unblocked.
         *
         * If a NetworkCallback object implements this method,
         * {@link #onBlockedStatusChanged(Network, boolean)} will not be called.
         *
         * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
         * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
         * this callback as this is prone to race conditions : calling these methods while in a
         * callback may return an outdated or even a null object.
         *
         * @param network The {@link Network} whose blocked status has changed.
         * @param blocked The blocked status of this {@link Network}.
         * @hide
         */
        @SystemApi(client = MODULE_LIBRARIES)
        public void onBlockedStatusChanged(@NonNull Network network, @BlockedReason int blocked) {
            onBlockedStatusChanged(network, blocked != 0);
        }

        private NetworkRequest networkRequest;
        private final int mFlags;
    }
@@ -3733,7 +3792,7 @@ public class ConnectivityManager {
                case CALLBACK_AVAILABLE: {
                    NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
                    LinkProperties lp = getObject(message, LinkProperties.class);
                    callback.onAvailable(network, cap, lp, message.arg1 != 0);
                    callback.onAvailable(network, cap, lp, message.arg1);
                    break;
                }
                case CALLBACK_LOSING: {
@@ -3767,8 +3826,7 @@ public class ConnectivityManager {
                    break;
                }
                case CALLBACK_BLK_CHANGED: {
                    boolean blocked = message.arg1 != 0;
                    callback.onBlockedStatusChanged(network, blocked);
                    callback.onBlockedStatusChanged(network, message.arg1);
                }
            }
        }
@@ -5371,4 +5429,23 @@ public class ConnectivityManager {
        if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_MODE_OPPORTUNISTIC;
        return mode;
    }

    /**
     * Set private DNS mode to settings.
     *
     * @param context The {@link Context} to set the private DNS mode.
     * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
     *
     * @hide
     */
    @SystemApi(client = MODULE_LIBRARIES)
    public static void setPrivateDnsMode(@NonNull Context context,
            @NonNull @PrivateDnsMode String mode) {
        if (!(mode == PRIVATE_DNS_MODE_OFF
                || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
                || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
            throw new IllegalArgumentException("Invalid private dns mode");
        }
        Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, mode);
    }
}
+689 −1

File changed.

Preview size limit exceeded, changes collapsed.

+43 −29
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTI
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN;
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
@@ -108,6 +110,7 @@ import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.BlockedReason;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager.RestrictBackgroundStatus;
import android.net.ConnectivityResources;
@@ -2338,15 +2341,15 @@ public class ConnectivityService extends IConnectivityManager.Stub

    private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() {
        @Override
        public void onUidBlockedReasonChanged(int uid, int blockedReasons) {
        public void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
            mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED,
                    uid, blockedReasons));
        }
    };

    void handleUidBlockedReasonChanged(int uid, int blockedReasons) {
    private void handleUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
        maybeNotifyNetworkBlockedForNewState(uid, blockedReasons);
        mUidBlockedReasons.put(uid, blockedReasons);
        setUidBlockedReasons(uid, blockedReasons);
    }

    private boolean checkAnyPermissionOf(String... permissions) {
@@ -8052,12 +8055,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
            return;
        }

        final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
        final boolean metered = nai.networkCapabilities.isMetered();
        boolean blocked;
        blocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges);
        blocked |= NetworkPolicyManager.isUidBlocked(
                mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE), metered);
        callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
        final boolean vpnBlocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges);
        callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE,
                getBlockedState(blockedReasons, metered, vpnBlocked));
    }

    // Notify the requests on this NAI that the network is now lingered.
@@ -8066,6 +8068,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
        notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
    }

    private static int getBlockedState(int reasons, boolean metered, boolean vpnBlocked) {
        if (!metered) reasons &= ~BLOCKED_METERED_REASON_MASK;
        return vpnBlocked
                ? reasons | BLOCKED_REASON_LOCKDOWN_VPN
                : reasons & ~BLOCKED_REASON_LOCKDOWN_VPN;
    }

    private void setUidBlockedReasons(int uid, @BlockedReason int blockedReasons) {
        if (blockedReasons == BLOCKED_REASON_NONE) {
            mUidBlockedReasons.delete(uid);
        } else {
            mUidBlockedReasons.put(uid, blockedReasons);
        }
    }

    /**
     * Notify of the blocked state apps with a registered callback matching a given NAI.
     *
@@ -8073,7 +8090,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
     * 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 oldMetered True if the previous network capabilities were metered.
     * @param newMetered True if the current network capabilities are metered.
     * @param oldBlockedUidRanges list of UID ranges previously blocked by lockdown VPN.
     * @param newBlockedUidRanges list of UID ranges blocked by lockdown VPN.
     */
    private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered,
            boolean newMetered, List<UidRange> oldBlockedUidRanges,
@@ -8082,22 +8102,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
        for (int i = 0; i < nai.numNetworkRequests(); i++) {
            NetworkRequest nr = nai.requestAt(i);
            NetworkRequestInfo nri = mNetworkRequests.get(nr);
            final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked;

            oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges);
            newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
            final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
            final boolean oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges);
            final boolean newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
                    ? isUidBlockedByVpn(nri.mAsUid, newBlockedUidRanges)
                    : oldVpnBlocked;

            final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
            oldBlocked = oldVpnBlocked || NetworkPolicyManager.isUidBlocked(
                    blockedReasons, oldMetered);
            newBlocked = newVpnBlocked || NetworkPolicyManager.isUidBlocked(
                    blockedReasons, newMetered);

            if (oldBlocked != newBlocked) {
            final int oldBlockedState = getBlockedState(blockedReasons, oldMetered, oldVpnBlocked);
            final int newBlockedState = getBlockedState(blockedReasons, newMetered, newVpnBlocked);
            if (oldBlockedState != newBlockedState) {
                callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
                        encodeBool(newBlocked));
                        newBlockedState);
            }
        }
    }
@@ -8107,25 +8123,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
     * @param uid The uid for which the rules changed.
     * @param blockedReasons The reasons for why an uid is blocked.
     */
    private void maybeNotifyNetworkBlockedForNewState(int uid, int blockedReasons) {
    private void maybeNotifyNetworkBlockedForNewState(int uid, @BlockedReason int blockedReasons) {
        for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
            final boolean metered = nai.networkCapabilities.isMetered();
            final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges);
            final boolean oldBlocked, newBlocked;

            oldBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked(
                    mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered);
            newBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked(
                    blockedReasons, metered);
            if (oldBlocked == newBlocked) {
            final int oldBlockedState = getBlockedState(
                    mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered, vpnBlocked);
            final int newBlockedState = getBlockedState(blockedReasons, metered, vpnBlocked);
            if (oldBlockedState == newBlockedState) {
                continue;
            }
            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.mAsUid == uid) {
                    callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg);
                    callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
                            newBlockedState);
                }
            }
        }
Loading