summaryrefslogtreecommitdiff
path: root/tests/net/java/com/android/server/ConnectivityServiceTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/net/java/com/android/server/ConnectivityServiceTest.java')
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java12792
1 files changed, 0 insertions, 12792 deletions
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
deleted file mode 100644
index 63501d7662ed..000000000000
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ /dev/null
@@ -1,12792 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.Manifest.permission.CHANGE_NETWORK_STATE;
-import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
-import static android.Manifest.permission.DUMP;
-import static android.Manifest.permission.LOCAL_MAC_ADDRESS;
-import static android.Manifest.permission.NETWORK_FACTORY;
-import static android.Manifest.permission.NETWORK_SETTINGS;
-import static android.app.PendingIntent.FLAG_IMMUTABLE;
-import static android.content.Intent.ACTION_PACKAGE_ADDED;
-import static android.content.Intent.ACTION_PACKAGE_REMOVED;
-import static android.content.Intent.ACTION_PACKAGE_REPLACED;
-import static android.content.Intent.ACTION_USER_ADDED;
-import static android.content.Intent.ACTION_USER_REMOVED;
-import static android.content.Intent.ACTION_USER_UNLOCKED;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
-import static android.content.pm.PackageManager.FEATURE_WIFI;
-import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
-import static android.content.pm.PackageManager.GET_PERMISSIONS;
-import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
-import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
-import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
-import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
-import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
-import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
-import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
-import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
-import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
-import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
-import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
-import static android.net.ConnectivityManager.TYPE_PROXY;
-import static android.net.ConnectivityManager.TYPE_VPN;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
-import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
-import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
-import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
-import static android.net.NetworkCapabilities.REDACT_NONE;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkScore.KEEP_CONNECTED_FOR_HANDOVER;
-import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
-import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
-import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
-import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
-import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
-import static android.net.RouteInfo.RTN_UNREACHABLE;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
-import static android.os.Process.INVALID_UID;
-import static android.system.OsConstants.IPPROTO_TCP;
-
-import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
-import static com.android.testutils.ConcurrentUtils.await;
-import static com.android.testutils.ConcurrentUtils.durationOf;
-import static com.android.testutils.ExceptionUtils.ignoreExceptions;
-import static com.android.testutils.HandlerUtils.waitForIdleSerialExecutor;
-import static com.android.testutils.MiscAsserts.assertContainsAll;
-import static com.android.testutils.MiscAsserts.assertContainsExactly;
-import static com.android.testutils.MiscAsserts.assertEmpty;
-import static com.android.testutils.MiscAsserts.assertLength;
-import static com.android.testutils.MiscAsserts.assertRunsInAtMost;
-import static com.android.testutils.MiscAsserts.assertThrows;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.AdditionalMatchers.aryEq;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.ArgumentMatchers.startsWith;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.app.AppOpsManager;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.usage.NetworkStatsManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.location.LocationManager;
-import android.net.CaptivePortalData;
-import android.net.ConnectionInfo;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.ConnectivityManager.PacketKeepalive;
-import android.net.ConnectivityManager.PacketKeepaliveCallback;
-import android.net.ConnectivityManager.TooManyRequestsException;
-import android.net.ConnectivityResources;
-import android.net.ConnectivitySettingsManager;
-import android.net.ConnectivityThread;
-import android.net.DataStallReportParcelable;
-import android.net.EthernetManager;
-import android.net.IConnectivityDiagnosticsCallback;
-import android.net.IDnsResolver;
-import android.net.INetd;
-import android.net.INetworkMonitor;
-import android.net.INetworkMonitorCallbacks;
-import android.net.IOnCompleteListener;
-import android.net.IQosCallback;
-import android.net.InetAddresses;
-import android.net.InterfaceConfigurationParcel;
-import android.net.IpPrefix;
-import android.net.IpSecManager;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.MatchAllNetworkSpecifier;
-import android.net.NativeNetworkConfig;
-import android.net.NativeNetworkType;
-import android.net.Network;
-import android.net.NetworkAgent;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkFactory;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkPolicyManager.NetworkPolicyCallback;
-import android.net.NetworkRequest;
-import android.net.NetworkScore;
-import android.net.NetworkSpecifier;
-import android.net.NetworkStack;
-import android.net.NetworkStateSnapshot;
-import android.net.NetworkTestResultParcelable;
-import android.net.OemNetworkPreferences;
-import android.net.ProxyInfo;
-import android.net.QosCallbackException;
-import android.net.QosFilter;
-import android.net.QosSession;
-import android.net.ResolverParamsParcel;
-import android.net.RouteInfo;
-import android.net.RouteInfoParcel;
-import android.net.SocketKeepalive;
-import android.net.TransportInfo;
-import android.net.UidRange;
-import android.net.UidRangeParcel;
-import android.net.UnderlyingNetworkInfo;
-import android.net.Uri;
-import android.net.VpnManager;
-import android.net.VpnTransportInfo;
-import android.net.metrics.IpConnectivityLog;
-import android.net.networkstack.NetworkStackClientBase;
-import android.net.resolv.aidl.Nat64PrefixEventParcel;
-import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
-import android.net.shared.NetworkMonitorUtils;
-import android.net.shared.PrivateDnsConfig;
-import android.net.util.MultinetworkPolicyTracker;
-import android.os.BadParcelableException;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.INetworkManagementService;
-import android.os.Looper;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.os.SystemClock;
-import android.os.SystemConfigManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.security.Credentials;
-import android.system.Os;
-import android.telephony.TelephonyManager;
-import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.telephony.data.NrQosSessionAttributes;
-import android.test.mock.MockContentResolver;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Range;
-import android.util.SparseArray;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.connectivity.resources.R;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.WakeupMessage;
-import com.android.internal.util.test.BroadcastInterceptingContext;
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.net.module.util.ArrayTrackRecord;
-import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
-import com.android.server.connectivity.MockableSystemProperties;
-import com.android.server.connectivity.Nat464Xlat;
-import com.android.server.connectivity.NetworkAgentInfo;
-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import com.android.server.connectivity.ProxyTracker;
-import com.android.server.connectivity.QosCallbackTracker;
-import com.android.server.connectivity.Vpn;
-import com.android.server.connectivity.VpnProfileStore;
-import com.android.server.net.NetworkPinner;
-import com.android.testutils.ExceptionUtils;
-import com.android.testutils.HandlerUtils;
-import com.android.testutils.RecorderCallback.CallbackEntry;
-import com.android.testutils.TestableNetworkCallback;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.AdditionalAnswers;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-import org.mockito.stubbing.Answer;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.net.DatagramSocket;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import kotlin.reflect.KClass;
-
-/**
- * Tests for {@link ConnectivityService}.
- *
- * Build, install and run with:
- * runtest frameworks-net -c com.android.server.ConnectivityServiceTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConnectivityServiceTest {
- private static final String TAG = "ConnectivityServiceTest";
-
- private static final int TIMEOUT_MS = 500;
- // Broadcasts can take a long time to be delivered. The test will not wait for that long unless
- // there is a failure, so use a long timeout.
- private static final int BROADCAST_TIMEOUT_MS = 30_000;
- private static final int TEST_LINGER_DELAY_MS = 400;
- private static final int TEST_NASCENT_DELAY_MS = 300;
- // Chosen to be less than the linger and nascent timeout. This ensures that we can distinguish
- // between a LOST callback that arrives immediately and a LOST callback that arrives after
- // the linger/nascent timeout. For this, our assertions should run fast enough to leave
- // less than (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
- // supposedly fired, and the time we call expectCallback.
- private static final int TEST_CALLBACK_TIMEOUT_MS = 250;
- // Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to
- // complete before callbacks are verified.
- private static final int TEST_REQUEST_TIMEOUT_MS = 150;
-
- private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000;
-
- private static final long TIMESTAMP = 1234L;
-
- private static final int NET_ID = 110;
- private static final int OEM_PREF_ANY_NET_ID = -1;
- // Set a non-zero value to verify the flow to set tcp init rwnd value.
- private static final int TEST_TCP_INIT_RWND = 60;
-
- // Used for testing the per-work-profile default network.
- private static final int TEST_APP_ID = 103;
- private static final int TEST_WORK_PROFILE_USER_ID = 2;
- private static final int TEST_WORK_PROFILE_APP_UID =
- UserHandle.getUid(TEST_WORK_PROFILE_USER_ID, TEST_APP_ID);
- private static final String CLAT_PREFIX = "v4-";
- private static final String MOBILE_IFNAME = "test_rmnet_data0";
- private static final String WIFI_IFNAME = "test_wlan0";
- private static final String WIFI_WOL_IFNAME = "test_wlan_wol";
- private static final String VPN_IFNAME = "tun10042";
- private static final String TEST_PACKAGE_NAME = "com.android.test.package";
- private static final int TEST_PACKAGE_UID = 123;
- private static final String ALWAYS_ON_PACKAGE = "com.android.test.alwaysonvpn";
-
- private static final String INTERFACE_NAME = "interface";
-
- private static final String TEST_VENUE_URL_NA_PASSPOINT = "https://android.com/";
- private static final String TEST_VENUE_URL_NA_OTHER = "https://example.com/";
- private static final String TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT =
- "https://android.com/terms/";
- private static final String TEST_TERMS_AND_CONDITIONS_URL_NA_OTHER =
- "https://example.com/terms/";
- private static final String TEST_VENUE_URL_CAPPORT = "https://android.com/capport/";
- private static final String TEST_USER_PORTAL_API_URL_CAPPORT =
- "https://android.com/user/api/capport/";
- private static final String TEST_FRIENDLY_NAME = "Network friendly name";
- private static final String TEST_REDIRECT_URL = "http://example.com/firstPath";
-
- private MockContext mServiceContext;
- private HandlerThread mCsHandlerThread;
- private HandlerThread mVMSHandlerThread;
- private ConnectivityService.Dependencies mDeps;
- private ConnectivityService mService;
- private WrappedConnectivityManager mCm;
- private TestNetworkAgentWrapper mWiFiNetworkAgent;
- private TestNetworkAgentWrapper mCellNetworkAgent;
- private TestNetworkAgentWrapper mEthernetNetworkAgent;
- private MockVpn mMockVpn;
- private Context mContext;
- private NetworkPolicyCallback mPolicyCallback;
- private WrappedMultinetworkPolicyTracker mPolicyTracker;
- private HandlerThread mAlarmManagerThread;
- private TestNetIdManager mNetIdManager;
- private QosCallbackMockHelper mQosCallbackMockHelper;
- private QosCallbackTracker mQosCallbackTracker;
- private VpnManagerService mVpnManagerService;
- private TestNetworkCallback mDefaultNetworkCallback;
- private TestNetworkCallback mSystemDefaultNetworkCallback;
- private TestNetworkCallback mProfileDefaultNetworkCallback;
-
- // State variables required to emulate NetworkPolicyManagerService behaviour.
- private int mBlockedReasons = BLOCKED_REASON_NONE;
-
- @Mock DeviceIdleInternal mDeviceIdleInternal;
- @Mock INetworkManagementService mNetworkManagementService;
- @Mock NetworkStatsManager mStatsManager;
- @Mock IDnsResolver mMockDnsResolver;
- @Mock INetd mMockNetd;
- @Mock NetworkStackClientBase mNetworkStack;
- @Mock PackageManager mPackageManager;
- @Mock UserManager mUserManager;
- @Mock NotificationManager mNotificationManager;
- @Mock AlarmManager mAlarmManager;
- @Mock IConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback;
- @Mock IBinder mIBinder;
- @Mock LocationManager mLocationManager;
- @Mock AppOpsManager mAppOpsManager;
- @Mock TelephonyManager mTelephonyManager;
- @Mock MockableSystemProperties mSystemProperties;
- @Mock EthernetManager mEthernetManager;
- @Mock NetworkPolicyManager mNetworkPolicyManager;
- @Mock VpnProfileStore mVpnProfileStore;
- @Mock SystemConfigManager mSystemConfigManager;
- @Mock Resources mResources;
-
- private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
- ArgumentCaptor.forClass(ResolverParamsParcel.class);
-
- // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
- // do not go through ConnectivityService but talk to netd directly, so they don't automatically
- // reflect the state of our test ConnectivityService.
- private class WrappedConnectivityManager extends ConnectivityManager {
- private Network mFakeBoundNetwork;
-
- public synchronized boolean bindProcessToNetwork(Network network) {
- mFakeBoundNetwork = network;
- return true;
- }
-
- public synchronized Network getBoundNetworkForProcess() {
- return mFakeBoundNetwork;
- }
-
- public WrappedConnectivityManager(Context context, ConnectivityService service) {
- super(context, service);
- }
- }
-
- private class MockContext extends BroadcastInterceptingContext {
- private final MockContentResolver mContentResolver;
-
- @Spy private Resources mInternalResources;
- private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
-
- // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
- private final HashMap<String, Integer> mMockedPermissions = new HashMap<>();
-
- MockContext(Context base, ContentProvider settingsProvider) {
- super(base);
-
- mInternalResources = spy(base.getResources());
- when(mInternalResources.getStringArray(com.android.internal.R.array.networkAttributes))
- .thenReturn(new String[] {
- "wifi,1,1,1,-1,true",
- "mobile,0,0,0,-1,true",
- "mobile_mms,2,0,2,60000,true",
- "mobile_supl,3,0,2,60000,true",
- });
-
- mContentResolver = new MockContentResolver();
- mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
- }
-
- @Override
- public void startActivityAsUser(Intent intent, UserHandle handle) {
- mStartedActivities.offer(intent);
- }
-
- public Intent expectStartActivityIntent(int timeoutMs) {
- Intent intent = null;
- try {
- intent = mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {}
- assertNotNull("Did not receive sign-in intent after " + timeoutMs + "ms", intent);
- return intent;
- }
-
- public void expectNoStartActivityIntent(int timeoutMs) {
- try {
- assertNull("Received unexpected Intent to start activity",
- mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS));
- } catch (InterruptedException e) {}
- }
-
- @Override
- public ComponentName startService(Intent service) {
- final String action = service.getAction();
- if (!VpnConfig.SERVICE_INTERFACE.equals(action)) {
- fail("Attempt to start unknown service, action=" + action);
- }
- return new ComponentName(service.getPackage(), "com.android.test.Service");
- }
-
- @Override
- public Object getSystemService(String name) {
- if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
- if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
- if (Context.USER_SERVICE.equals(name)) return mUserManager;
- if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
- if (Context.LOCATION_SERVICE.equals(name)) return mLocationManager;
- if (Context.APP_OPS_SERVICE.equals(name)) return mAppOpsManager;
- if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
- if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager;
- if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
- if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager;
- if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
- return super.getSystemService(name);
- }
-
- final HashMap<UserHandle, UserManager> mUserManagers = new HashMap<>();
- @Override
- public Context createContextAsUser(UserHandle user, int flags) {
- final Context asUser = mock(Context.class, AdditionalAnswers.delegatesTo(this));
- doReturn(user).when(asUser).getUser();
- doAnswer((inv) -> {
- final UserManager um = mUserManagers.computeIfAbsent(user,
- u -> mock(UserManager.class, AdditionalAnswers.delegatesTo(mUserManager)));
- return um;
- }).when(asUser).getSystemService(Context.USER_SERVICE);
- return asUser;
- }
-
- public void setWorkProfile(@NonNull final UserHandle userHandle, boolean value) {
- // This relies on all contexts for a given user returning the same UM mock
- final UserManager umMock = createContextAsUser(userHandle, 0 /* flags */)
- .getSystemService(UserManager.class);
- doReturn(value).when(umMock).isManagedProfile();
- doReturn(value).when(mUserManager).isManagedProfile(eq(userHandle.getIdentifier()));
- }
-
- @Override
- public ContentResolver getContentResolver() {
- return mContentResolver;
- }
-
- @Override
- public Resources getResources() {
- return mInternalResources;
- }
-
- @Override
- public PackageManager getPackageManager() {
- return mPackageManager;
- }
-
- private int checkMockedPermission(String permission, Supplier<Integer> ifAbsent) {
- final Integer granted = mMockedPermissions.get(permission);
- return granted != null ? granted : ifAbsent.get();
- }
-
- @Override
- public int checkPermission(String permission, int pid, int uid) {
- return checkMockedPermission(
- permission, () -> super.checkPermission(permission, pid, uid));
- }
-
- @Override
- public int checkCallingOrSelfPermission(String permission) {
- return checkMockedPermission(
- permission, () -> super.checkCallingOrSelfPermission(permission));
- }
-
- @Override
- public void enforceCallingOrSelfPermission(String permission, String message) {
- final Integer granted = mMockedPermissions.get(permission);
- if (granted == null) {
- super.enforceCallingOrSelfPermission(permission, message);
- return;
- }
-
- if (!granted.equals(PERMISSION_GRANTED)) {
- throw new SecurityException("[Test] permission denied: " + permission);
- }
- }
-
- /**
- * Mock checks for the specified permission, and have them behave as per {@code granted}.
- *
- * <p>Passing null reverts to default behavior, which does a real permission check on the
- * test package.
- * @param granted One of {@link PackageManager#PERMISSION_GRANTED} or
- * {@link PackageManager#PERMISSION_DENIED}.
- */
- public void setPermission(String permission, Integer granted) {
- mMockedPermissions.put(permission, granted);
- }
- }
-
- private void waitForIdle() {
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
- waitForIdle(mCellNetworkAgent, TIMEOUT_MS);
- waitForIdle(mWiFiNetworkAgent, TIMEOUT_MS);
- waitForIdle(mEthernetNetworkAgent, TIMEOUT_MS);
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
- HandlerUtils.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
- }
-
- private void waitForIdle(TestNetworkAgentWrapper agent, long timeoutMs) {
- if (agent == null) {
- return;
- }
- agent.waitForIdle(timeoutMs);
- }
-
- @Test
- public void testWaitForIdle() throws Exception {
- final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
-
- // Tests that waitForIdle returns immediately if the service is already idle.
- for (int i = 0; i < attempts; i++) {
- waitForIdle();
- }
-
- // Bring up a network that we can use to send messages to ConnectivityService.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- Network n = mWiFiNetworkAgent.getNetwork();
- assertNotNull(n);
-
- // Tests that calling waitForIdle waits for messages to be processed.
- for (int i = 0; i < attempts; i++) {
- mWiFiNetworkAgent.setSignalStrength(i);
- waitForIdle();
- assertEquals(i, mCm.getNetworkCapabilities(n).getSignalStrength());
- }
- }
-
- // This test has an inherent race condition in it, and cannot be enabled for continuous testing
- // or presubmit tests. It is kept for manual runs and documentation purposes.
- @Ignore
- public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception {
- // Bring up a network that we can use to send messages to ConnectivityService.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- Network n = mWiFiNetworkAgent.getNetwork();
- assertNotNull(n);
-
- // Ensure that not calling waitForIdle causes a race condition.
- final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
- for (int i = 0; i < attempts; i++) {
- mWiFiNetworkAgent.setSignalStrength(i);
- if (i != mCm.getNetworkCapabilities(n).getSignalStrength()) {
- // We hit a race condition, as expected. Pass the test.
- return;
- }
- }
-
- // No race? There is a bug in this test.
- fail("expected race condition at least once in " + attempts + " attempts");
- }
-
- private class TestNetworkAgentWrapper extends NetworkAgentWrapper {
- private static final int VALIDATION_RESULT_INVALID = 0;
-
- private static final long DATA_STALL_TIMESTAMP = 10L;
- private static final int DATA_STALL_DETECTION_METHOD = 1;
-
- private INetworkMonitor mNetworkMonitor;
- private INetworkMonitorCallbacks mNmCallbacks;
- private int mNmValidationResult = VALIDATION_RESULT_INVALID;
- private int mProbesCompleted;
- private int mProbesSucceeded;
- private String mNmValidationRedirectUrl = null;
- private boolean mNmProvNotificationRequested = false;
- private Runnable mCreatedCallback;
- private Runnable mUnwantedCallback;
- private Runnable mDisconnectedCallback;
-
- private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
- // Contains the redirectUrl from networkStatus(). Before reading, wait for
- // mNetworkStatusReceived.
- private String mRedirectUrl;
-
- TestNetworkAgentWrapper(int transport) throws Exception {
- this(transport, new LinkProperties(), null);
- }
-
- TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
- throws Exception {
- this(transport, linkProperties, null);
- }
-
- private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
- NetworkCapabilities ncTemplate) throws Exception {
- super(transport, linkProperties, ncTemplate, mServiceContext);
-
- // Waits for the NetworkAgent to be registered, which includes the creation of the
- // NetworkMonitor.
- waitForIdle(TIMEOUT_MS);
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
- HandlerUtils.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
- }
-
- @Override
- protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
- NetworkAgentConfig nac) throws Exception {
- mNetworkMonitor = mock(INetworkMonitor.class);
-
- final Answer validateAnswer = inv -> {
- new Thread(ignoreExceptions(this::onValidationRequested)).start();
- return null;
- };
-
- doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected(any(), any());
- doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
-
- final ArgumentCaptor<Network> nmNetworkCaptor = ArgumentCaptor.forClass(Network.class);
- final ArgumentCaptor<INetworkMonitorCallbacks> nmCbCaptor =
- ArgumentCaptor.forClass(INetworkMonitorCallbacks.class);
- doNothing().when(mNetworkStack).makeNetworkMonitor(
- nmNetworkCaptor.capture(),
- any() /* name */,
- nmCbCaptor.capture());
-
- final InstrumentedNetworkAgent na =
- new InstrumentedNetworkAgent(this, linkProperties, nac) {
- @Override
- public void networkStatus(int status, String redirectUrl) {
- mRedirectUrl = redirectUrl;
- mNetworkStatusReceived.open();
- }
-
- @Override
- public void onNetworkCreated() {
- super.onNetworkCreated();
- if (mCreatedCallback != null) mCreatedCallback.run();
- }
-
- @Override
- public void onNetworkUnwanted() {
- super.onNetworkUnwanted();
- if (mUnwantedCallback != null) mUnwantedCallback.run();
- }
-
- @Override
- public void onNetworkDestroyed() {
- super.onNetworkDestroyed();
- if (mDisconnectedCallback != null) mDisconnectedCallback.run();
- }
- };
-
- assertEquals(na.getNetwork().netId, nmNetworkCaptor.getValue().netId);
- mNmCallbacks = nmCbCaptor.getValue();
-
- mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
-
- return na;
- }
-
- private void onValidationRequested() throws Exception {
- if (mNmProvNotificationRequested
- && ((mNmValidationResult & NETWORK_VALIDATION_RESULT_VALID) != 0)) {
- mNmCallbacks.hideProvisioningNotification();
- mNmProvNotificationRequested = false;
- }
-
- mNmCallbacks.notifyProbeStatusChanged(mProbesCompleted, mProbesSucceeded);
- final NetworkTestResultParcelable p = new NetworkTestResultParcelable();
- p.result = mNmValidationResult;
- p.probesAttempted = mProbesCompleted;
- p.probesSucceeded = mProbesSucceeded;
- p.redirectUrl = mNmValidationRedirectUrl;
- p.timestampMillis = TIMESTAMP;
- mNmCallbacks.notifyNetworkTestedWithExtras(p);
-
- if (mNmValidationRedirectUrl != null) {
- mNmCallbacks.showProvisioningNotification(
- "test_provisioning_notif_action", TEST_PACKAGE_NAME);
- mNmProvNotificationRequested = true;
- }
- }
-
- /**
- * Connect without adding any internet capability.
- */
- public void connectWithoutInternet() {
- super.connect();
- }
-
- /**
- * Transition this NetworkAgent to CONNECTED state with NET_CAPABILITY_INTERNET.
- * @param validated Indicate if network should pretend to be validated.
- */
- public void connect(boolean validated) {
- connect(validated, true, false /* isStrictMode */);
- }
-
- /**
- * Transition this NetworkAgent to CONNECTED state.
- * @param validated Indicate if network should pretend to be validated.
- * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
- */
- public void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
- assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET));
-
- ConnectivityManager.NetworkCallback callback = null;
- final ConditionVariable validatedCv = new ConditionVariable();
- if (validated) {
- setNetworkValid(isStrictMode);
- NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(getNetworkCapabilities().getTransportTypes()[0])
- .clearCapabilities()
- .build();
- callback = new ConnectivityManager.NetworkCallback() {
- public void onCapabilitiesChanged(Network network,
- NetworkCapabilities networkCapabilities) {
- if (network.equals(getNetwork()) &&
- networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
- validatedCv.open();
- }
- }
- };
- mCm.registerNetworkCallback(request, callback);
- }
- if (hasInternet) {
- addCapability(NET_CAPABILITY_INTERNET);
- }
-
- connectWithoutInternet();
-
- if (validated) {
- // Wait for network to validate.
- waitFor(validatedCv);
- setNetworkInvalid(isStrictMode);
- }
-
- if (callback != null) mCm.unregisterNetworkCallback(callback);
- }
-
- public void connectWithCaptivePortal(String redirectUrl, boolean isStrictMode) {
- setNetworkPortal(redirectUrl, isStrictMode);
- connect(false, true /* hasInternet */, isStrictMode);
- }
-
- public void connectWithPartialConnectivity() {
- setNetworkPartial();
- connect(false);
- }
-
- public void connectWithPartialValidConnectivity(boolean isStrictMode) {
- setNetworkPartialValid(isStrictMode);
- connect(false, true /* hasInternet */, isStrictMode);
- }
-
- void setNetworkValid(boolean isStrictMode) {
- mNmValidationResult = NETWORK_VALIDATION_RESULT_VALID;
- mNmValidationRedirectUrl = null;
- int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS;
- if (isStrictMode) {
- probesSucceeded |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- // The probesCompleted equals to probesSucceeded for the case of valid network, so put
- // the same value into two different parameter of the method.
- setProbesStatus(probesSucceeded, probesSucceeded);
- }
-
- void setNetworkInvalid(boolean isStrictMode) {
- mNmValidationResult = VALIDATION_RESULT_INVALID;
- mNmValidationRedirectUrl = null;
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_PROBE_HTTP;
- int probesSucceeded = 0;
- // If the isStrictMode is true, it means the network is invalid when NetworkMonitor
- // tried to validate the private DNS but failed.
- if (isStrictMode) {
- probesCompleted &= ~NETWORK_VALIDATION_PROBE_HTTP;
- probesSucceeded = probesCompleted;
- probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setNetworkPortal(String redirectUrl, boolean isStrictMode) {
- setNetworkInvalid(isStrictMode);
- mNmValidationRedirectUrl = redirectUrl;
- // Suppose the portal is found when NetworkMonitor probes NETWORK_VALIDATION_PROBE_HTTP
- // in the beginning, so the NETWORK_VALIDATION_PROBE_HTTPS hasn't probed yet.
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP;
- int probesSucceeded = VALIDATION_RESULT_INVALID;
- if (isStrictMode) {
- probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setNetworkPartial() {
- mNmValidationResult = NETWORK_VALIDATION_RESULT_PARTIAL;
- mNmValidationRedirectUrl = null;
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_PROBE_FALLBACK;
- int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_FALLBACK;
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setNetworkPartialValid(boolean isStrictMode) {
- setNetworkPartial();
- mNmValidationResult |= NETWORK_VALIDATION_RESULT_VALID;
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_PROBE_HTTP;
- int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP;
- // Suppose the partial network cannot pass the private DNS validation as well, so only
- // add NETWORK_VALIDATION_PROBE_DNS in probesCompleted but not probesSucceeded.
- if (isStrictMode) {
- probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setProbesStatus(int probesCompleted, int probesSucceeded) {
- mProbesCompleted = probesCompleted;
- mProbesSucceeded = probesSucceeded;
- }
-
- void notifyCapportApiDataChanged(CaptivePortalData data) {
- try {
- mNmCallbacks.notifyCaptivePortalDataChanged(data);
- } catch (RemoteException e) {
- throw new AssertionError("This cannot happen", e);
- }
- }
-
- public String waitForRedirectUrl() {
- assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS));
- return mRedirectUrl;
- }
-
- public void expectDisconnected() {
- expectDisconnected(TIMEOUT_MS);
- }
-
- public void expectPreventReconnectReceived() {
- expectPreventReconnectReceived(TIMEOUT_MS);
- }
-
- void notifyDataStallSuspected() throws Exception {
- final DataStallReportParcelable p = new DataStallReportParcelable();
- p.detectionMethod = DATA_STALL_DETECTION_METHOD;
- p.timestampMillis = DATA_STALL_TIMESTAMP;
- mNmCallbacks.notifyDataStallSuspected(p);
- }
-
- public void setCreatedCallback(Runnable r) {
- mCreatedCallback = r;
- }
-
- public void setUnwantedCallback(Runnable r) {
- mUnwantedCallback = r;
- }
-
- public void setDisconnectedCallback(Runnable r) {
- mDisconnectedCallback = r;
- }
- }
-
- /**
- * A NetworkFactory that allows to wait until any in-flight NetworkRequest add or remove
- * operations have been processed and test for them.
- */
- private static class MockNetworkFactory extends NetworkFactory {
- private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
-
- static class RequestEntry {
- @NonNull
- public final NetworkRequest request;
-
- RequestEntry(@NonNull final NetworkRequest request) {
- this.request = request;
- }
-
- static final class Add extends RequestEntry {
- Add(@NonNull final NetworkRequest request) {
- super(request);
- }
- }
-
- static final class Remove extends RequestEntry {
- Remove(@NonNull final NetworkRequest request) {
- super(request);
- }
- }
-
- @Override
- public String toString() {
- return "RequestEntry [ " + getClass().getName() + " : " + request + " ]";
- }
- }
-
- // History of received requests adds and removes.
- private final ArrayTrackRecord<RequestEntry>.ReadHead mRequestHistory =
- new ArrayTrackRecord<RequestEntry>().newReadHead();
-
- private static <T> T failIfNull(@Nullable final T obj, @Nullable final String message) {
- if (null == obj) fail(null != message ? message : "Must not be null");
- return obj;
- }
-
- public RequestEntry.Add expectRequestAdd() {
- return failIfNull((RequestEntry.Add) mRequestHistory.poll(TIMEOUT_MS,
- it -> it instanceof RequestEntry.Add), "Expected request add");
- }
-
- public void expectRequestAdds(final int count) {
- for (int i = count; i > 0; --i) {
- expectRequestAdd();
- }
- }
-
- public RequestEntry.Remove expectRequestRemove() {
- return failIfNull((RequestEntry.Remove) mRequestHistory.poll(TIMEOUT_MS,
- it -> it instanceof RequestEntry.Remove), "Expected request remove");
- }
-
- public void expectRequestRemoves(final int count) {
- for (int i = count; i > 0; --i) {
- expectRequestRemove();
- }
- }
-
- // Used to collect the networks requests managed by this factory. This is a duplicate of
- // the internal information stored in the NetworkFactory (which is private).
- private SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
- private final HandlerThread mHandlerSendingRequests;
-
- public MockNetworkFactory(Looper looper, Context context, String logTag,
- NetworkCapabilities filter, HandlerThread threadSendingRequests) {
- super(looper, context, logTag, filter);
- mHandlerSendingRequests = threadSendingRequests;
- }
-
- public int getMyRequestCount() {
- return getRequestCount();
- }
-
- protected void startNetwork() {
- mNetworkStarted.set(true);
- }
-
- protected void stopNetwork() {
- mNetworkStarted.set(false);
- }
-
- public boolean getMyStartRequested() {
- return mNetworkStarted.get();
- }
-
-
- @Override
- protected void needNetworkFor(NetworkRequest request) {
- mNetworkRequests.put(request.requestId, request);
- super.needNetworkFor(request);
- mRequestHistory.add(new RequestEntry.Add(request));
- }
-
- @Override
- protected void releaseNetworkFor(NetworkRequest request) {
- mNetworkRequests.remove(request.requestId);
- super.releaseNetworkFor(request);
- mRequestHistory.add(new RequestEntry.Remove(request));
- }
-
- public void assertRequestCountEquals(final int count) {
- assertEquals(count, getMyRequestCount());
- }
-
- @Override
- public void terminate() {
- super.terminate();
- // Make sure there are no remaining requests unaccounted for.
- HandlerUtils.waitForIdle(mHandlerSendingRequests, TIMEOUT_MS);
- assertNull(mRequestHistory.poll(0, r -> true));
- }
-
- // Trigger releasing the request as unfulfillable
- public void triggerUnfulfillable(NetworkRequest r) {
- super.releaseRequestAsUnfulfillableByAnyFactory(r);
- }
-
- public void assertNoRequestChanged() {
- assertNull(mRequestHistory.poll(0, r -> true));
- }
- }
-
- private Set<UidRange> uidRangesForUids(int... uids) {
- final ArraySet<UidRange> ranges = new ArraySet<>();
- for (final int uid : uids) {
- ranges.add(new UidRange(uid, uid));
- }
- return ranges;
- }
-
- private static Looper startHandlerThreadAndReturnLooper() {
- final HandlerThread handlerThread = new HandlerThread("MockVpnThread");
- handlerThread.start();
- return handlerThread.getLooper();
- }
-
- private class MockVpn extends Vpn implements TestableNetworkCallback.HasNetwork {
- // Careful ! This is different from mNetworkAgent, because MockNetworkAgent does
- // not inherit from NetworkAgent.
- private TestNetworkAgentWrapper mMockNetworkAgent;
- private boolean mAgentRegistered = false;
-
- private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
- private UnderlyingNetworkInfo mUnderlyingNetworkInfo;
-
- // These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started.
- // TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the
- // test expects two starts in a row, or even if the production code calls start twice in a
- // row. find a better solution. Simply putting a method to create a LegacyVpnRunner into
- // Vpn.Dependencies doesn't work because LegacyVpnRunner is not a static class and has
- // extensive access into the internals of Vpn.
- private ConditionVariable mStartLegacyVpnCv = new ConditionVariable();
- private ConditionVariable mStopVpnRunnerCv = new ConditionVariable();
-
- public MockVpn(int userId) {
- super(startHandlerThreadAndReturnLooper(), mServiceContext,
- new Dependencies() {
- @Override
- public boolean isCallerSystem() {
- return true;
- }
-
- @Override
- public DeviceIdleInternal getDeviceIdleInternal() {
- return mDeviceIdleInternal;
- }
- },
- mNetworkManagementService, mMockNetd, userId, mVpnProfileStore);
- }
-
- public void setUids(Set<UidRange> uids) {
- mNetworkCapabilities.setUids(UidRange.toIntRanges(uids));
- if (mAgentRegistered) {
- mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true);
- }
- }
-
- public void setVpnType(int vpnType) {
- mVpnType = vpnType;
- }
-
- @Override
- public Network getNetwork() {
- return (mMockNetworkAgent == null) ? null : mMockNetworkAgent.getNetwork();
- }
-
- @Override
- public int getActiveVpnType() {
- return mVpnType;
- }
-
- private LinkProperties makeLinkProperties() {
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(VPN_IFNAME);
- return lp;
- }
-
- private void registerAgent(boolean isAlwaysMetered, Set<UidRange> uids, LinkProperties lp)
- throws Exception {
- if (mAgentRegistered) throw new IllegalStateException("already registered");
- updateState(NetworkInfo.DetailedState.CONNECTING, "registerAgent");
- mConfig = new VpnConfig();
- mConfig.session = "MySession12345";
- setUids(uids);
- if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
- mInterface = VPN_IFNAME;
- mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType(),
- mConfig.session));
- mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
- mNetworkCapabilities);
- mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
-
- verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
- eq(toUidRangeStableParcels(uids)));
- verify(mMockNetd, never())
- .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()), any());
- mAgentRegistered = true;
- verify(mMockNetd).networkCreate(nativeNetworkConfigVpn(getNetwork().netId,
- !mMockNetworkAgent.isBypassableVpn(), mVpnType));
- updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent");
- mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
- mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
- }
-
- private void registerAgent(Set<UidRange> uids) throws Exception {
- registerAgent(false /* isAlwaysMetered */, uids, makeLinkProperties());
- }
-
- private void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
- mMockNetworkAgent.connect(validated, hasInternet, isStrictMode);
- }
-
- private void connect(boolean validated) {
- mMockNetworkAgent.connect(validated);
- }
-
- private TestNetworkAgentWrapper getAgent() {
- return mMockNetworkAgent;
- }
-
- public void establish(LinkProperties lp, int uid, Set<UidRange> ranges, boolean validated,
- boolean hasInternet, boolean isStrictMode) throws Exception {
- mNetworkCapabilities.setOwnerUid(uid);
- mNetworkCapabilities.setAdministratorUids(new int[]{uid});
- registerAgent(false, ranges, lp);
- connect(validated, hasInternet, isStrictMode);
- waitForIdle();
- }
-
- public void establish(LinkProperties lp, int uid, Set<UidRange> ranges) throws Exception {
- establish(lp, uid, ranges, true, true, false);
- }
-
- public void establishForMyUid(LinkProperties lp) throws Exception {
- final int uid = Process.myUid();
- establish(lp, uid, uidRangesForUids(uid), true, true, false);
- }
-
- public void establishForMyUid(boolean validated, boolean hasInternet, boolean isStrictMode)
- throws Exception {
- final int uid = Process.myUid();
- establish(makeLinkProperties(), uid, uidRangesForUids(uid), validated, hasInternet,
- isStrictMode);
- }
-
- public void establishForMyUid() throws Exception {
- establishForMyUid(makeLinkProperties());
- }
-
- public void sendLinkProperties(LinkProperties lp) {
- mMockNetworkAgent.sendLinkProperties(lp);
- }
-
- public void disconnect() {
- if (mMockNetworkAgent != null) {
- mMockNetworkAgent.disconnect();
- updateState(NetworkInfo.DetailedState.DISCONNECTED, "disconnect");
- }
- mAgentRegistered = false;
- setUids(null);
- // Remove NET_CAPABILITY_INTERNET or MockNetworkAgent will refuse to connect later on.
- mNetworkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
- mInterface = null;
- }
-
- @Override
- public void startLegacyVpnRunner() {
- mStartLegacyVpnCv.open();
- }
-
- public void expectStartLegacyVpnRunner() {
- assertTrue("startLegacyVpnRunner not called after " + TIMEOUT_MS + " ms",
- mStartLegacyVpnCv.block(TIMEOUT_MS));
-
- // startLegacyVpn calls stopVpnRunnerPrivileged, which will open mStopVpnRunnerCv, just
- // before calling startLegacyVpnRunner. Restore mStopVpnRunnerCv, so the test can expect
- // that the VpnRunner is stopped and immediately restarted by calling
- // expectStartLegacyVpnRunner() and expectStopVpnRunnerPrivileged() back-to-back.
- mStopVpnRunnerCv = new ConditionVariable();
- }
-
- @Override
- public void stopVpnRunnerPrivileged() {
- if (mVpnRunner != null) {
- super.stopVpnRunnerPrivileged();
- disconnect();
- mStartLegacyVpnCv = new ConditionVariable();
- }
- mVpnRunner = null;
- mStopVpnRunnerCv.open();
- }
-
- public void expectStopVpnRunnerPrivileged() {
- assertTrue("stopVpnRunnerPrivileged not called after " + TIMEOUT_MS + " ms",
- mStopVpnRunnerCv.block(TIMEOUT_MS));
- }
-
- @Override
- public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
- if (mUnderlyingNetworkInfo != null) return mUnderlyingNetworkInfo;
-
- return super.getUnderlyingNetworkInfo();
- }
-
- private synchronized void setUnderlyingNetworkInfo(
- UnderlyingNetworkInfo underlyingNetworkInfo) {
- mUnderlyingNetworkInfo = underlyingNetworkInfo;
- }
- }
-
- private UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) {
- return ranges.stream().map(
- r -> new UidRangeParcel(r.start, r.stop)).toArray(UidRangeParcel[]::new);
- }
-
- private VpnManagerService makeVpnManagerService() {
- final VpnManagerService.Dependencies deps = new VpnManagerService.Dependencies() {
- public int getCallingUid() {
- return mDeps.getCallingUid();
- }
-
- public HandlerThread makeHandlerThread() {
- return mVMSHandlerThread;
- }
-
- @Override
- public VpnProfileStore getVpnProfileStore() {
- return mVpnProfileStore;
- }
-
- public INetd getNetd() {
- return mMockNetd;
- }
-
- public INetworkManagementService getINetworkManagementService() {
- return mNetworkManagementService;
- }
- };
- return new VpnManagerService(mServiceContext, deps);
- }
-
- private void assertVpnTransportInfo(NetworkCapabilities nc, int type) {
- assertNotNull(nc);
- final TransportInfo ti = nc.getTransportInfo();
- assertTrue("VPN TransportInfo is not a VpnTransportInfo: " + ti,
- ti instanceof VpnTransportInfo);
- assertEquals(type, ((VpnTransportInfo) ti).getType());
-
- }
-
- private void processBroadcast(Intent intent) {
- mServiceContext.sendBroadcast(intent);
- HandlerUtils.waitForIdle(mVMSHandlerThread, TIMEOUT_MS);
- waitForIdle();
- }
-
- private void mockVpn(int uid) {
- synchronized (mVpnManagerService.mVpns) {
- int userId = UserHandle.getUserId(uid);
- mMockVpn = new MockVpn(userId);
- // Every running user always has a Vpn in the mVpns array, even if no VPN is running.
- mVpnManagerService.mVpns.put(userId, mMockVpn);
- }
- }
-
- private void mockUidNetworkingBlocked() {
- doAnswer(i -> isUidBlocked(mBlockedReasons, i.getArgument(1))
- ).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
- }
-
- private boolean isUidBlocked(int blockedReasons, boolean meteredNetwork) {
- final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK);
- if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) {
- return true;
- }
- if (meteredNetwork) {
- return blockedReasons != BLOCKED_REASON_NONE;
- }
- return false;
- }
-
- private void setBlockedReasonChanged(int blockedReasons) {
- mBlockedReasons = blockedReasons;
- mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons);
- }
-
- private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
- return mService.getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
- }
-
- private static class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
- volatile boolean mConfigRestrictsAvoidBadWifi;
- volatile int mConfigMeteredMultipathPreference;
-
- WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
- super(c, h, r);
- }
-
- @Override
- public boolean configRestrictsAvoidBadWifi() {
- return mConfigRestrictsAvoidBadWifi;
- }
-
- @Override
- public int configMeteredMultipathPreference() {
- return mConfigMeteredMultipathPreference;
- }
- }
-
- /**
- * Wait up to TIMEOUT_MS for {@code conditionVariable} to open.
- * Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
- */
- static private void waitFor(ConditionVariable conditionVariable) {
- if (conditionVariable.block(TIMEOUT_MS)) {
- return;
- }
- fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms");
- }
-
- private <T> T doAsUid(final int uid, @NonNull final Supplier<T> what) {
- when(mDeps.getCallingUid()).thenReturn(uid);
- try {
- return what.get();
- } finally {
- returnRealCallingUid();
- }
- }
-
- private void doAsUid(final int uid, @NonNull final Runnable what) {
- doAsUid(uid, () -> {
- what.run(); return Void.TYPE;
- });
- }
-
- private void registerNetworkCallbackAsUid(NetworkRequest request, NetworkCallback callback,
- int uid) {
- doAsUid(uid, () -> {
- mCm.registerNetworkCallback(request, callback);
- });
- }
-
- private void registerDefaultNetworkCallbackAsUid(@NonNull final NetworkCallback callback,
- final int uid) {
- doAsUid(uid, () -> {
- mCm.registerDefaultNetworkCallback(callback);
- waitForIdle();
- });
- }
-
- private interface ExceptionalRunnable {
- void run() throws Exception;
- }
-
- private void withPermission(String permission, ExceptionalRunnable r) throws Exception {
- if (mServiceContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
- r.run();
- return;
- }
- try {
- mServiceContext.setPermission(permission, PERMISSION_GRANTED);
- r.run();
- } finally {
- mServiceContext.setPermission(permission, PERMISSION_DENIED);
- }
- }
-
- private static final int PRIMARY_USER = 0;
- private static final UidRange PRIMARY_UIDRANGE =
- UidRange.createForUser(UserHandle.of(PRIMARY_USER));
- private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
- private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101);
- private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043);
- private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
- UserInfo.FLAG_PRIMARY);
- private static final UserHandle PRIMARY_USER_HANDLE = new UserHandle(PRIMARY_USER);
-
- private static final int RESTRICTED_USER = 1;
- private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
- UserInfo.FLAG_RESTRICTED);
- static {
- RESTRICTED_USER_INFO.restrictedProfileParentId = PRIMARY_USER;
- }
-
- @Before
- public void setUp() throws Exception {
- mNetIdManager = new TestNetIdManager();
-
- mContext = InstrumentationRegistry.getContext();
-
- MockitoAnnotations.initMocks(this);
-
- when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE));
- when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO);
- // canHaveRestrictedProfile does not take a userId. It applies to the userId of the context
- // it was started from, i.e., PRIMARY_USER.
- when(mUserManager.canHaveRestrictedProfile()).thenReturn(true);
- when(mUserManager.getUserInfo(RESTRICTED_USER)).thenReturn(RESTRICTED_USER_INFO);
-
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
- .thenReturn(applicationInfo);
- when(mPackageManager.getTargetSdkVersion(anyString()))
- .thenReturn(applicationInfo.targetSdkVersion);
- when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
-
- // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
- // http://b/25897652 .
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
- mockDefaultPackages();
- mockHasSystemFeature(FEATURE_WIFI, true);
- mockHasSystemFeature(FEATURE_WIFI_DIRECT, true);
- doReturn(true).when(mTelephonyManager).isDataCapable();
-
- FakeSettingsProvider.clearSettingsProvider();
- mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
- new FakeSettingsProvider());
- mServiceContext.setUseRegisteredHandlers(true);
-
- mAlarmManagerThread = new HandlerThread("TestAlarmManager");
- mAlarmManagerThread.start();
- initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
-
- mCsHandlerThread = new HandlerThread("TestConnectivityService");
- mVMSHandlerThread = new HandlerThread("TestVpnManagerService");
- mDeps = makeDependencies();
- returnRealCallingUid();
- mService = new ConnectivityService(mServiceContext,
- mMockDnsResolver,
- mock(IpConnectivityLog.class),
- mMockNetd,
- mDeps);
- mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
- mService.mNascentDelayMs = TEST_NASCENT_DELAY_MS;
- verify(mDeps).makeMultinetworkPolicyTracker(any(), any(), any());
-
- final ArgumentCaptor<NetworkPolicyCallback> policyCallbackCaptor =
- ArgumentCaptor.forClass(NetworkPolicyCallback.class);
- verify(mNetworkPolicyManager).registerNetworkPolicyCallback(any(),
- policyCallbackCaptor.capture());
- mPolicyCallback = policyCallbackCaptor.getValue();
-
- // Create local CM before sending system ready so that we can answer
- // getSystemService() correctly.
- mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
- mService.systemReadyInternal();
- mVpnManagerService = makeVpnManagerService();
- mVpnManagerService.systemReady();
- mockVpn(Process.myUid());
- mCm.bindProcessToNetwork(null);
- mQosCallbackTracker = mock(QosCallbackTracker.class);
-
- // Ensure that the default setting for Captive Portals is used for most tests
- setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
- setAlwaysOnNetworks(false);
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
- }
-
- private void returnRealCallingUid() {
- doAnswer((invocationOnMock) -> Binder.getCallingUid()).when(mDeps).getCallingUid();
- }
-
- private ConnectivityService.Dependencies makeDependencies() {
- doReturn(false).when(mSystemProperties).getBoolean("ro.radio.noril", false);
- final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class);
- doReturn(mCsHandlerThread).when(deps).makeHandlerThread();
- doReturn(mNetIdManager).when(deps).makeNetIdManager();
- doReturn(mNetworkStack).when(deps).getNetworkStack();
- doReturn(mSystemProperties).when(deps).getSystemProperties();
- doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
- doReturn(true).when(deps).queryUserAccess(anyInt(), any(), any());
- doAnswer(inv -> {
- mPolicyTracker = new WrappedMultinetworkPolicyTracker(
- inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
- return mPolicyTracker;
- }).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
- doReturn(true).when(deps).getCellular464XlatEnabled();
-
- doReturn(60000).when(mResources).getInteger(R.integer.config_networkTransitionTimeout);
- doReturn("").when(mResources).getString(R.string.config_networkCaptivePortalServerUrl);
- doReturn(new String[]{ WIFI_WOL_IFNAME }).when(mResources).getStringArray(
- R.array.config_wakeonlan_supported_interfaces);
- doReturn(new String[] { "0,1", "1,3" }).when(mResources).getStringArray(
- R.array.config_networkSupportedKeepaliveCount);
- doReturn(new String[0]).when(mResources).getStringArray(
- R.array.config_networkNotifySwitches);
- doReturn(new int[]{10, 11, 12, 14, 15}).when(mResources).getIntArray(
- R.array.config_protectedNetworks);
- // We don't test the actual notification value strings, so just return an empty array.
- // It doesn't matter what the values are as long as it's not null.
- doReturn(new String[0]).when(mResources).getStringArray(R.array.network_switch_type_name);
-
- doReturn(R.array.config_networkSupportedKeepaliveCount).when(mResources)
- .getIdentifier(eq("config_networkSupportedKeepaliveCount"), eq("array"), any());
- doReturn(R.array.network_switch_type_name).when(mResources)
- .getIdentifier(eq("network_switch_type_name"), eq("array"), any());
-
-
- final ConnectivityResources connRes = mock(ConnectivityResources.class);
- doReturn(mResources).when(connRes).get();
- doReturn(connRes).when(deps).getResources(any());
-
- final Context mockResContext = mock(Context.class);
- doReturn(mResources).when(mockResContext).getResources();
- ConnectivityResources.setResourcesContextForTest(mockResContext);
-
- return deps;
- }
-
- private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) {
- doAnswer(inv -> {
- final long when = inv.getArgument(1);
- final WakeupMessage wakeupMsg = inv.getArgument(3);
- final Handler handler = inv.getArgument(4);
-
- long delayMs = when - SystemClock.elapsedRealtime();
- if (delayMs < 0) delayMs = 0;
- if (delayMs > UNREASONABLY_LONG_ALARM_WAIT_MS) {
- fail("Attempting to send msg more than " + UNREASONABLY_LONG_ALARM_WAIT_MS
- + "ms into the future: " + delayMs);
- }
- alarmHandler.postDelayed(() -> handler.post(wakeupMsg::onAlarm), wakeupMsg /* token */,
- delayMs);
-
- return null;
- }).when(am).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(), anyString(),
- any(WakeupMessage.class), any());
-
- doAnswer(inv -> {
- final WakeupMessage wakeupMsg = inv.getArgument(0);
- alarmHandler.removeCallbacksAndMessages(wakeupMsg /* token */);
- return null;
- }).when(am).cancel(any(WakeupMessage.class));
- }
-
- @After
- public void tearDown() throws Exception {
- unregisterDefaultNetworkCallbacks();
- maybeTearDownEnterpriseNetwork();
- setAlwaysOnNetworks(false);
- if (mCellNetworkAgent != null) {
- mCellNetworkAgent.disconnect();
- mCellNetworkAgent = null;
- }
- if (mWiFiNetworkAgent != null) {
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent = null;
- }
- if (mEthernetNetworkAgent != null) {
- mEthernetNetworkAgent.disconnect();
- mEthernetNetworkAgent = null;
- }
-
- if (mQosCallbackMockHelper != null) {
- mQosCallbackMockHelper.tearDown();
- mQosCallbackMockHelper = null;
- }
- mMockVpn.disconnect();
- waitForIdle();
-
- FakeSettingsProvider.clearSettingsProvider();
- ConnectivityResources.setResourcesContextForTest(null);
-
- mCsHandlerThread.quitSafely();
- mAlarmManagerThread.quitSafely();
- }
-
- private void mockDefaultPackages() throws Exception {
- final String myPackageName = mContext.getPackageName();
- final PackageInfo myPackageInfo = mContext.getPackageManager().getPackageInfo(
- myPackageName, PackageManager.GET_PERMISSIONS);
- when(mPackageManager.getPackagesForUid(Binder.getCallingUid())).thenReturn(
- new String[] {myPackageName});
- when(mPackageManager.getPackageInfoAsUser(eq(myPackageName), anyInt(),
- eq(UserHandle.getCallingUserId()))).thenReturn(myPackageInfo);
-
- when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- Arrays.asList(new PackageInfo[] {
- buildPackageInfo(/* SYSTEM */ false, APP1_UID),
- buildPackageInfo(/* SYSTEM */ false, APP2_UID),
- buildPackageInfo(/* SYSTEM */ false, VPN_UID)
- }));
-
- // Create a fake always-on VPN package.
- final int userId = UserHandle.getCallingUserId();
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; // Always-on supported in N+.
- when(mPackageManager.getApplicationInfoAsUser(eq(ALWAYS_ON_PACKAGE), anyInt(),
- eq(userId))).thenReturn(applicationInfo);
-
- // Minimal mocking to keep Vpn#isAlwaysOnPackageSupported happy.
- ResolveInfo rInfo = new ResolveInfo();
- rInfo.serviceInfo = new ServiceInfo();
- rInfo.serviceInfo.metaData = new Bundle();
- final List<ResolveInfo> services = Arrays.asList(new ResolveInfo[]{rInfo});
- when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
- eq(userId))).thenReturn(services);
- when(mPackageManager.getPackageUidAsUser(TEST_PACKAGE_NAME, userId))
- .thenReturn(Process.myUid());
- when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, userId))
- .thenReturn(VPN_UID);
- }
-
- private void verifyActiveNetwork(int transport) {
- // Test getActiveNetworkInfo()
- assertNotNull(mCm.getActiveNetworkInfo());
- assertEquals(transportToLegacyType(transport), mCm.getActiveNetworkInfo().getType());
- // Test getActiveNetwork()
- assertNotNull(mCm.getActiveNetwork());
- assertEquals(mCm.getActiveNetwork(), mCm.getActiveNetworkForUid(Process.myUid()));
- if (!NetworkCapabilities.isValidTransport(transport)) {
- throw new IllegalStateException("Unknown transport " + transport);
- }
- switch (transport) {
- case TRANSPORT_WIFI:
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- break;
- case TRANSPORT_CELLULAR:
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- break;
- case TRANSPORT_ETHERNET:
- assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- break;
- default:
- break;
- }
- // Test getNetworkInfo(Network)
- assertNotNull(mCm.getNetworkInfo(mCm.getActiveNetwork()));
- assertEquals(transportToLegacyType(transport),
- mCm.getNetworkInfo(mCm.getActiveNetwork()).getType());
- assertNotNull(mCm.getActiveNetworkInfoForUid(Process.myUid()));
- // Test getNetworkCapabilities(Network)
- assertNotNull(mCm.getNetworkCapabilities(mCm.getActiveNetwork()));
- assertTrue(mCm.getNetworkCapabilities(mCm.getActiveNetwork()).hasTransport(transport));
- }
-
- private void verifyNoNetwork() {
- waitForIdle();
- // Test getActiveNetworkInfo()
- assertNull(mCm.getActiveNetworkInfo());
- // Test getActiveNetwork()
- assertNull(mCm.getActiveNetwork());
- assertNull(mCm.getActiveNetworkForUid(Process.myUid()));
- // Test getAllNetworks()
- assertEmpty(mCm.getAllNetworks());
- assertEmpty(mCm.getAllNetworkStateSnapshots());
- }
-
- /**
- * Class to simplify expecting broadcasts using BroadcastInterceptingContext.
- * Ensures that the receiver is unregistered after the expected broadcast is received. This
- * cannot be done in the BroadcastReceiver itself because BroadcastInterceptingContext runs
- * the receivers' receive method while iterating over the list of receivers, and unregistering
- * the receiver during iteration throws ConcurrentModificationException.
- */
- private class ExpectedBroadcast extends CompletableFuture<Intent> {
- private final BroadcastReceiver mReceiver;
-
- ExpectedBroadcast(BroadcastReceiver receiver) {
- mReceiver = receiver;
- }
-
- public Intent expectBroadcast(int timeoutMs) throws Exception {
- try {
- return get(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- fail("Expected broadcast not received after " + timeoutMs + " ms");
- return null;
- } finally {
- mServiceContext.unregisterReceiver(mReceiver);
- }
- }
-
- public Intent expectBroadcast() throws Exception {
- return expectBroadcast(BROADCAST_TIMEOUT_MS);
- }
-
- public void expectNoBroadcast(int timeoutMs) throws Exception {
- waitForIdle();
- try {
- final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS);
- fail("Unexpected broadcast: " + intent.getAction() + " " + intent.getExtras());
- } catch (TimeoutException expected) {
- } finally {
- mServiceContext.unregisterReceiver(mReceiver);
- }
- }
- }
-
- /** Expects that {@code count} CONNECTIVITY_ACTION broadcasts are received. */
- private ExpectedBroadcast registerConnectivityBroadcast(final int count) {
- return registerConnectivityBroadcastThat(count, intent -> true);
- }
-
- private ExpectedBroadcast registerConnectivityBroadcastThat(final int count,
- @NonNull final Predicate<Intent> filter) {
- final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION);
- // AtomicReference allows receiver to access expected even though it is constructed later.
- final AtomicReference<ExpectedBroadcast> expectedRef = new AtomicReference<>();
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- private int mRemaining = count;
- public void onReceive(Context context, Intent intent) {
- final int type = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1);
- final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO);
- Log.d(TAG, "Received CONNECTIVITY_ACTION type=" + type + " ni=" + ni);
- if (!filter.test(intent)) return;
- if (--mRemaining == 0) {
- expectedRef.get().complete(intent);
- }
- }
- };
- final ExpectedBroadcast expected = new ExpectedBroadcast(receiver);
- expectedRef.set(expected);
- mServiceContext.registerReceiver(receiver, intentFilter);
- return expected;
- }
-
- private boolean extraInfoInBroadcastHasExpectedNullness(NetworkInfo ni) {
- final DetailedState state = ni.getDetailedState();
- if (state == DetailedState.CONNECTED && ni.getExtraInfo() == null) return false;
- // Expect a null extraInfo if the network is CONNECTING, because a CONNECTIVITY_ACTION
- // broadcast with a state of CONNECTING only happens due to legacy VPN lockdown, which also
- // nulls out extraInfo.
- if (state == DetailedState.CONNECTING && ni.getExtraInfo() != null) return false;
- // Can't make any assertions about DISCONNECTED broadcasts. When a network actually
- // disconnects, disconnectAndDestroyNetwork sets its state to DISCONNECTED and its extraInfo
- // to null. But if the DISCONNECTED broadcast is just simulated by LegacyTypeTracker due to
- // a network switch, extraInfo will likely be populated.
- // This is likely a bug in CS, but likely not one we can fix without impacting apps.
- return true;
- }
-
- private ExpectedBroadcast expectConnectivityAction(int type, NetworkInfo.DetailedState state) {
- return registerConnectivityBroadcastThat(1, intent -> {
- final int actualType = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1);
- final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO);
- return type == actualType
- && state == ni.getDetailedState()
- && extraInfoInBroadcastHasExpectedNullness(ni);
- });
- }
-
- @Test
- public void testNetworkTypes() {
- // Ensure that our mocks for the networkAttributes config variable work as expected. If they
- // don't, then tests that depend on CONNECTIVITY_ACTION broadcasts for these network types
- // will fail. Failing here is much easier to debug.
- assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
- assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
- assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_MMS));
- assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
- assertFalse(mCm.isNetworkSupported(TYPE_PROXY));
-
- // Check that TYPE_ETHERNET is supported. Unlike the asserts above, which only validate our
- // mocks, this assert exercises the ConnectivityService code path that ensures that
- // TYPE_ETHERNET is supported if the ethernet service is running.
- assertTrue(mCm.isNetworkSupported(TYPE_ETHERNET));
- }
-
- @Test
- public void testNetworkFeature() throws Exception {
- // Connect the cell agent and wait for the connected broadcast.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_SUPL);
- ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
-
- // Build legacy request for SUPL.
- final NetworkCapabilities legacyCaps = new NetworkCapabilities();
- legacyCaps.addTransportType(TRANSPORT_CELLULAR);
- legacyCaps.addCapability(NET_CAPABILITY_SUPL);
- final NetworkRequest legacyRequest = new NetworkRequest(legacyCaps, TYPE_MOBILE_SUPL,
- ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST);
-
- // File request, withdraw it and make sure no broadcast is sent
- b = registerConnectivityBroadcast(1);
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.requestNetwork(legacyRequest, callback);
- callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- mCm.unregisterNetworkCallback(callback);
- b.expectNoBroadcast(800); // 800ms long enough to at least flake if this is sent
-
- // Disconnect the network and expect mobile disconnected broadcast.
- b = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- }
-
- @Test
- public void testLingering() throws Exception {
- verifyNoNetwork();
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- assertNull(mCm.getActiveNetworkInfo());
- assertNull(mCm.getActiveNetwork());
- // Test bringing up validated cellular.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- assertLength(2, mCm.getAllNetworks());
- assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
- mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
- assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) ||
- mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork()));
- // Test bringing up validated WiFi.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertLength(2, mCm.getAllNetworks());
- assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
- mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
- assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
- mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
- // Test cellular linger timeout.
- mCellNetworkAgent.expectDisconnected();
- waitForIdle();
- assertLength(1, mCm.getAllNetworks());
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertLength(1, mCm.getAllNetworks());
- assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
- // Test WiFi disconnect.
- b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyNoNetwork();
- }
-
- /**
- * Verify a newly created network will be inactive instead of torn down even if no one is
- * requesting.
- */
- @Test
- public void testNewNetworkInactive() throws Exception {
- // Create a callback that monitoring the testing network.
- final TestNetworkCallback listenCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), listenCallback);
-
- // 1. Create a network that is not requested by anyone, and does not satisfy any of the
- // default requests. Verify that the network will be inactive instead of torn down.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithoutInternet();
- listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- listenCallback.assertNoCallback();
-
- // Verify that the network will be torn down after nascent expiry. A small period of time
- // is added in case of flakiness.
- final int nascentTimeoutMs =
- mService.mNascentDelayMs + mService.mNascentDelayMs / 4;
- listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent, nascentTimeoutMs);
-
- // 2. Create a network that is satisfied by a request comes later.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithoutInternet();
- listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final TestNetworkCallback wifiCallback = new TestNetworkCallback();
- mCm.requestNetwork(wifiRequest, wifiCallback);
- wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Verify that the network will be kept since the request is still satisfied. And is able
- // to get disconnected as usual if the request is released after the nascent timer expires.
- listenCallback.assertNoCallback(nascentTimeoutMs);
- mCm.unregisterNetworkCallback(wifiCallback);
- listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // 3. Create a network that is satisfied by a request comes later.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithoutInternet();
- listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- mCm.requestNetwork(wifiRequest, wifiCallback);
- wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Verify that the network will still be torn down after the request gets removed.
- mCm.unregisterNetworkCallback(wifiCallback);
- listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // There is no need to ensure that LOSING is never sent in the common case that the
- // network immediately satisfies a request that was already present, because it is already
- // verified anywhere whenever {@code TestNetworkCallback#expectAvailable*} is called.
-
- mCm.unregisterNetworkCallback(listenCallback);
- }
-
- /**
- * Verify a newly created network will be inactive and switch to background if only background
- * request is satisfied.
- */
- @Test
- public void testNewNetworkInactive_bgNetwork() throws Exception {
- // Create a callback that monitoring the wifi network.
- final TestNetworkCallback wifiListenCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build(), wifiListenCallback);
-
- // Create callbacks that can monitor background and foreground mobile networks.
- // This is done by granting using background networks permission before registration. Thus,
- // the service will not add {@code NET_CAPABILITY_FOREGROUND} by default.
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- final TestNetworkCallback bgMobileListenCallback = new TestNetworkCallback();
- final TestNetworkCallback fgMobileListenCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build(), bgMobileListenCallback);
- mCm.registerNetworkCallback(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_FOREGROUND).build(), fgMobileListenCallback);
-
- // Connect wifi, which satisfies default request.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- wifiListenCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
-
- // Connect a cellular network, verify that satisfies only the background callback.
- setAlwaysOnNetworks(true);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- bgMobileListenCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- fgMobileListenCallback.assertNoCallback();
- assertFalse(isForegroundNetwork(mCellNetworkAgent));
-
- mCellNetworkAgent.disconnect();
- bgMobileListenCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- fgMobileListenCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(wifiListenCallback);
- mCm.unregisterNetworkCallback(bgMobileListenCallback);
- mCm.unregisterNetworkCallback(fgMobileListenCallback);
- }
-
- @Test
- public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
- // Test bringing up unvalidated WiFi
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up unvalidated cellular
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- waitForIdle();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test cellular disconnect.
- mCellNetworkAgent.disconnect();
- waitForIdle();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up validated cellular
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test cellular disconnect.
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test WiFi disconnect.
- b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyNoNetwork();
- }
-
- @Test
- public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
- // Test bringing up unvalidated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test WiFi disconnect.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test cellular disconnect.
- b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyNoNetwork();
- }
-
- @Test
- public void testUnlingeringDoesNotValidate() throws Exception {
- // Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- // Test cellular disconnect.
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Unlingering a network should not cause it to be marked as validated.
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- }
-
- @Test
- public void testCellularOutscoresWeakWifi() throws Exception {
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test WiFi getting really weak.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.adjustScore(-11);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test WiFi restoring signal strength.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.adjustScore(11);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testReapingNetwork() throws Exception {
- // Test bringing up WiFi without NET_CAPABILITY_INTERNET.
- // Expect it to be torn down immediately because it satisfies no requests.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithoutInternet();
- mWiFiNetworkAgent.expectDisconnected();
- // Test bringing up cellular without NET_CAPABILITY_INTERNET.
- // Expect it to be torn down immediately because it satisfies no requests.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mCellNetworkAgent.connectWithoutInternet();
- mCellNetworkAgent.expectDisconnected();
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up unvalidated cellular.
- // Expect it to be torn down because it could never be the highest scoring network
- // satisfying the default request even if it validated.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- mCellNetworkAgent.expectDisconnected();
- verifyActiveNetwork(TRANSPORT_WIFI);
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- }
-
- @Test
- public void testCellularFallback() throws Exception {
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Reevaluate WiFi (it'll instantly fail DNS).
- b = registerConnectivityBroadcast(2);
- assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
- // Should quickly fall back to Cellular.
- b.expectBroadcast();
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Reevaluate cellular (it'll instantly fail DNS).
- b = registerConnectivityBroadcast(2);
- assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
- // Should quickly fall back to WiFi.
- b.expectBroadcast();
- assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testWiFiFallback() throws Exception {
- // Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Reevaluate cellular (it'll instantly fail DNS).
- b = registerConnectivityBroadcast(2);
- assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
- // Should quickly fall back to WiFi.
- b.expectBroadcast();
- assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testRequiresValidation() {
- assertTrue(NetworkMonitorUtils.isValidationRequired(
- mCm.getDefaultRequest().networkCapabilities));
- }
-
- /**
- * Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
- * this class receives, by calling expectCallback() exactly once each time a callback is
- * received. assertNoCallback may be called at any time.
- */
- private class TestNetworkCallback extends TestableNetworkCallback {
- TestNetworkCallback() {
- super(TEST_CALLBACK_TIMEOUT_MS);
- }
-
- @Override
- public void assertNoCallback() {
- // TODO: better support this use case in TestableNetworkCallback
- waitForIdle();
- assertNoCallback(0 /* timeout */);
- }
-
- @Override
- public <T extends CallbackEntry> T expectCallback(final KClass<T> type, final HasNetwork n,
- final long timeoutMs) {
- final T callback = super.expectCallback(type, n, timeoutMs);
- if (callback instanceof CallbackEntry.Losing) {
- // TODO : move this to the specific test(s) needing this rather than here.
- final CallbackEntry.Losing losing = (CallbackEntry.Losing) callback;
- final int maxMsToLive = losing.getMaxMsToLive();
- String msg = String.format(
- "Invalid linger time value %d, must be between %d and %d",
- maxMsToLive, 0, mService.mLingerDelayMs);
- assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= mService.mLingerDelayMs);
- }
- return callback;
- }
- }
-
- // Can't be part of TestNetworkCallback because "cannot be declared static; static methods can
- // only be declared in a static or top level type".
- static void assertNoCallbacks(TestNetworkCallback ... callbacks) {
- for (TestNetworkCallback c : callbacks) {
- c.assertNoCallback();
- }
- }
-
- static void expectOnLost(TestNetworkAgentWrapper network, TestNetworkCallback ... callbacks) {
- for (TestNetworkCallback c : callbacks) {
- c.expectCallback(CallbackEntry.LOST, network);
- }
- }
-
- static void expectAvailableCallbacksUnvalidatedWithSpecifier(TestNetworkAgentWrapper network,
- NetworkSpecifier specifier, TestNetworkCallback ... callbacks) {
- for (TestNetworkCallback c : callbacks) {
- c.expectCallback(CallbackEntry.AVAILABLE, network);
- c.expectCapabilitiesThat(network, (nc) ->
- !nc.hasCapability(NET_CAPABILITY_VALIDATED)
- && Objects.equals(specifier, nc.getNetworkSpecifier()));
- c.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, network);
- c.expectCallback(CallbackEntry.BLOCKED_STATUS, network);
- }
- }
-
- @Test
- public void testStateChangeNetworkCallbacks() throws Exception {
- final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest genericRequest = new NetworkRequest.Builder()
- .clearCapabilities().build();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
-
- // Test unvalidated networks
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- // This should not trigger spurious onAvailable() callbacks, b/21762680.
- mCellNetworkAgent.adjustScore(-1);
- waitForIdle();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- // Test validated networks
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- // This should not trigger spurious onAvailable() callbacks, b/21762680.
- mCellNetworkAgent.adjustScore(-1);
- waitForIdle();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- genericNetworkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- }
-
- private void doNetworkCallbacksSanitizationTest(boolean sanitized) throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- mCm.registerNetworkCallback(wifiRequest, callback);
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- final LinkProperties newLp = new LinkProperties();
- final Uri capportUrl = Uri.parse("https://capport.example.com/api");
- final CaptivePortalData capportData = new CaptivePortalData.Builder()
- .setCaptive(true).build();
-
- final Uri expectedCapportUrl = sanitized ? null : capportUrl;
- newLp.setCaptivePortalApiUrl(capportUrl);
- mWiFiNetworkAgent.sendLinkProperties(newLp);
- callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
- defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
-
- final CaptivePortalData expectedCapportData = sanitized ? null : capportData;
- mWiFiNetworkAgent.notifyCapportApiDataChanged(capportData);
- callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
- defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
-
- final LinkProperties lp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork());
- assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl());
- assertEquals(expectedCapportData, lp.getCaptivePortalData());
- }
-
- @Test
- public void networkCallbacksSanitizationTest_Sanitize() throws Exception {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_DENIED);
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
- doNetworkCallbacksSanitizationTest(true /* sanitized */);
- }
-
- @Test
- public void networkCallbacksSanitizationTest_NoSanitize_NetworkStack() throws Exception {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_GRANTED);
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
- doNetworkCallbacksSanitizationTest(false /* sanitized */);
- }
-
- @Test
- public void networkCallbacksSanitizationTest_NoSanitize_Settings() throws Exception {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_DENIED);
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
- doNetworkCallbacksSanitizationTest(false /* sanitized */);
- }
-
- @Test
- public void testOwnerUidCannotChange() throws Exception {
- final NetworkCapabilities ncTemplate = new NetworkCapabilities();
- final int originalOwnerUid = Process.myUid();
- ncTemplate.setOwnerUid(originalOwnerUid);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
- ncTemplate);
- mWiFiNetworkAgent.connect(false);
- waitForIdle();
-
- // Send ConnectivityService an update to the mWiFiNetworkAgent's capabilities that changes
- // the owner UID and an unrelated capability.
- NetworkCapabilities agentCapabilities = mWiFiNetworkAgent.getNetworkCapabilities();
- assertEquals(originalOwnerUid, agentCapabilities.getOwnerUid());
- agentCapabilities.setOwnerUid(42);
- assertFalse(agentCapabilities.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- agentCapabilities.addCapability(NET_CAPABILITY_NOT_CONGESTED);
- mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true);
- waitForIdle();
-
- // Owner UIDs are not visible without location permission.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- // Check that the capability change has been applied but the owner UID is not modified.
- NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
- assertEquals(originalOwnerUid, nc.getOwnerUid());
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- }
-
- @Test
- public void testMultipleLingering() throws Exception {
- // This test would be flaky with the default 120ms timer: that is short enough that
- // lingered networks are torn down before assertions can be run. We don't want to mock the
- // lingering timer to keep the WakeupMessage logic realistic: this has already proven useful
- // in detecting races.
- mService.mLingerDelayMs = 300;
-
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_NOT_METERED)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
-
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
-
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent.connect(true);
- // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
- // We then get LOSING when wifi validates and cell is outscored.
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- for (int i = 0; i < 4; i++) {
- TestNetworkAgentWrapper oldNetwork, newNetwork;
- if (i % 2 == 0) {
- mWiFiNetworkAgent.adjustScore(-15);
- oldNetwork = mWiFiNetworkAgent;
- newNetwork = mCellNetworkAgent;
- } else {
- mWiFiNetworkAgent.adjustScore(15);
- oldNetwork = mCellNetworkAgent;
- newNetwork = mWiFiNetworkAgent;
-
- }
- callback.expectCallback(CallbackEntry.LOSING, oldNetwork);
- // TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
- // longer lingering?
- defaultCallback.expectAvailableCallbacksValidated(newNetwork);
- assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
- }
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even
- // if the network is still up.
- mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- // We expect a notification about the capabilities change, and nothing else.
- defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
- defaultCallback.assertNoCallback();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Wifi no longer satisfies our listen, which is for an unmetered network.
- // But because its score is 55, it's still up (and the default network).
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Disconnect our test networks.
- mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
-
- mCm.unregisterNetworkCallback(callback);
- waitForIdle();
-
- // Check that a network is only lingered or torn down if it would not satisfy a request even
- // if it validated.
- request = new NetworkRequest.Builder().clearCapabilities().build();
- callback = new TestNetworkCallback();
-
- mCm.registerNetworkCallback(request, callback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false); // Score: 10
- callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up wifi with a score of 20.
- // Cell stays up because it would satisfy the default request if it validated.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false); // Score: 20
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
- // it's arguably correct to linger it, since it was the default network before it validated.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
-
- // If a network is lingering, and we add and remove a request from it, resume lingering.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- NetworkCallback noopCallback = new NetworkCallback();
- mCm.requestNetwork(cellRequest, noopCallback);
- // TODO: should this cause an AVAILABLE callback, to indicate that the network is no longer
- // lingering?
- mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
-
- // Similar to the above: lingering can start even after the lingered request is removed.
- // Disconnect wifi and switch to cell.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Cell is now the default network. Pin it with a cell-specific request.
- noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525
- mCm.requestNetwork(cellRequest, noopCallback);
-
- // Now connect wifi, and expect it to become the default network.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- // The default request is lingering on cell, but nothing happens to cell, and we send no
- // callbacks for it, because it's kept up by cellRequest.
- callback.assertNoCallback();
- // Now unregister cellRequest and expect cell to start lingering.
- mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
-
- // Let linger run its course.
- callback.assertNoCallback();
- final int lingerTimeoutMs = mService.mLingerDelayMs + mService.mLingerDelayMs / 4;
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent, lingerTimeoutMs);
-
- // Register a TRACK_DEFAULT request and check that it does not affect lingering.
- TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(trackDefaultCallback);
- trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
- trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Let linger run its course.
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
-
- // Clean up.
- mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- trackDefaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
-
- mCm.unregisterNetworkCallback(callback);
- mCm.unregisterNetworkCallback(defaultCallback);
- mCm.unregisterNetworkCallback(trackDefaultCallback);
- }
-
- private void grantUsingBackgroundNetworksPermissionForUid(final int uid) throws Exception {
- grantUsingBackgroundNetworksPermissionForUid(uid, mContext.getPackageName());
- }
-
- private void grantUsingBackgroundNetworksPermissionForUid(
- final int uid, final String packageName) throws Exception {
- when(mPackageManager.getPackageInfo(
- eq(packageName), eq(GET_PERMISSIONS | MATCH_ANY_USER)))
- .thenReturn(buildPackageInfo(true /* hasSystemPermission */, uid));
- mService.mPermissionMonitor.onPackageAdded(packageName, uid);
- }
-
- @Test
- public void testNetworkGoesIntoBackgroundAfterLinger() throws Exception {
- setAlwaysOnNetworks(true);
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities()
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- // Wifi comes up and cell lingers.
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
-
- // File a request for cellular, then release it.
- NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- NetworkCallback noopCallback = new NetworkCallback();
- mCm.requestNetwork(cellRequest, noopCallback);
- mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
-
- // Let linger run its course.
- callback.assertNoCallback();
- final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
- callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent,
- lingerTimeoutMs);
-
- // Clean up.
- mCm.unregisterNetworkCallback(defaultCallback);
- mCm.unregisterNetworkCallback(callback);
- }
-
- private NativeNetworkConfig nativeNetworkConfigPhysical(int netId, int permission) {
- return new NativeNetworkConfig(netId, NativeNetworkType.PHYSICAL, permission,
- /*secure=*/ false, VpnManager.TYPE_VPN_NONE);
- }
-
- private NativeNetworkConfig nativeNetworkConfigVpn(int netId, boolean secure, int vpnType) {
- return new NativeNetworkConfig(netId, NativeNetworkType.VIRTUAL, INetd.PERMISSION_NONE,
- secure, vpnType);
- }
-
- @Test
- public void testNetworkAgentCallbacks() throws Exception {
- // Keeps track of the order of events that happen in this test.
- final LinkedBlockingQueue<String> eventOrder = new LinkedBlockingQueue<>();
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- final AtomicReference<Network> wifiNetwork = new AtomicReference<>();
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- // Expectations for state when various callbacks fire. These expectations run on the handler
- // thread and not on the test thread because they need to prevent the handler thread from
- // advancing while they examine state.
-
- // 1. When onCreated fires, netd has been told to create the network.
- mWiFiNetworkAgent.setCreatedCallback(() -> {
- eventOrder.offer("onNetworkCreated");
- wifiNetwork.set(mWiFiNetworkAgent.getNetwork());
- assertNotNull(wifiNetwork.get());
- try {
- verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- wifiNetwork.get().getNetId(), INetd.PERMISSION_NONE));
- } catch (RemoteException impossible) {
- fail();
- }
- });
-
- // 2. onNetworkUnwanted isn't precisely ordered with respect to any particular events. Just
- // check that it is fired at some point after disconnect.
- mWiFiNetworkAgent.setUnwantedCallback(() -> eventOrder.offer("onNetworkUnwanted"));
-
- // 3. While the teardown timer is running, connectivity APIs report the network is gone, but
- // netd has not yet been told to destroy it.
- final Runnable duringTeardown = () -> {
- eventOrder.offer("timePasses");
- assertNull(mCm.getLinkProperties(wifiNetwork.get()));
- try {
- verify(mMockNetd, never()).networkDestroy(wifiNetwork.get().getNetId());
- } catch (RemoteException impossible) {
- fail();
- }
- };
-
- // 4. After onNetworkDisconnected is called, connectivity APIs report the network is gone,
- // and netd has been told to destroy it.
- mWiFiNetworkAgent.setDisconnectedCallback(() -> {
- eventOrder.offer("onNetworkDisconnected");
- assertNull(mCm.getLinkProperties(wifiNetwork.get()));
- try {
- verify(mMockNetd).networkDestroy(wifiNetwork.get().getNetId());
- } catch (RemoteException impossible) {
- fail();
- }
- });
-
- // Connect a network, and file a request for it after it has come up, to ensure the nascent
- // timer is cleared and the test does not have to wait for it. Filing the request after the
- // network has come up is necessary because ConnectivityService does not appear to clear the
- // nascent timer if the first request satisfied by the network was filed before the network
- // connected.
- // TODO: fix this bug, file the request before connecting, and remove the waitForIdle.
- mWiFiNetworkAgent.connectWithoutInternet();
- waitForIdle();
- mCm.requestNetwork(request, callback);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Set teardown delay and make sure CS has processed it.
- mWiFiNetworkAgent.getNetworkAgent().setTeardownDelayMillis(300);
- waitForIdle();
-
- // Post the duringTeardown lambda to the handler so it fires while teardown is in progress.
- // The delay must be long enough it will run after the unregisterNetworkCallback has torn
- // down the network and started the teardown timer, and short enough that the lambda is
- // scheduled to run before the teardown timer.
- final Handler h = new Handler(mCsHandlerThread.getLooper());
- h.postDelayed(duringTeardown, 150);
-
- // Disconnect the network and check that events happened in the right order.
- mCm.unregisterNetworkCallback(callback);
- assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- assertEquals("onNetworkUnwanted", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- assertEquals("timePasses", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- assertEquals("onNetworkDisconnected", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- mCm.unregisterNetworkCallback(callback);
- }
-
- @Test
- public void testExplicitlySelected() throws Exception {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up validated cell.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- // Bring up unvalidated wifi with explicitlySelected=true.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, false);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Cell Remains the default.
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Lower wifi's score to below than cell, and check that it doesn't disconnect because
- // it's explicitly selected.
- mWiFiNetworkAgent.adjustScore(-40);
- mWiFiNetworkAgent.adjustScore(40);
- callback.assertNoCallback();
-
- // If the user chooses yes on the "No Internet access, stay connected?" dialog, we switch to
- // wifi even though it's unvalidated.
- mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), true, false);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Disconnect wifi, and then reconnect, again with explicitlySelected=true.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, false);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the
- // network to disconnect.
- mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), false, false);
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Reconnect, again with explicitlySelected=true, but this time validate.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, false);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
- assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- callback.assertNoCallback();
-
- // Disconnect wifi, and then reconnect as if the user had selected "yes, don't ask again"
- // (i.e., with explicitlySelected=true and acceptUnvalidated=true). Expect to switch to
- // wifi immediately.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, true);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mEthernetNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
-
- // Disconnect and reconnect with explicitlySelected=false and acceptUnvalidated=true.
- // Check that the network is not scored specially and that the device prefers cell data.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(false, true);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Clean up.
- mWiFiNetworkAgent.disconnect();
- mCellNetworkAgent.disconnect();
-
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- }
-
- private void tryNetworkFactoryRequests(int capability) throws Exception {
- // Verify NOT_RESTRICTED is set appropriately
- final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
- .build().networkCapabilities;
- if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN
- || capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA
- || capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS
- || capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
- || capability == NET_CAPABILITY_VSIM || capability == NET_CAPABILITY_BIP
- || capability == NET_CAPABILITY_ENTERPRISE) {
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- } else {
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- }
-
- NetworkCapabilities filter = new NetworkCapabilities();
- filter.addTransportType(TRANSPORT_CELLULAR);
- filter.addCapability(capability);
- // Add NOT_VCN_MANAGED capability into filter unconditionally since some requests will add
- // NOT_VCN_MANAGED automatically but not for NetworkCapabilities,
- // see {@code NetworkCapabilities#deduceNotVcnManagedCapability} for more details.
- filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
- handlerThread.start();
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- testFactory.setScoreFilter(45);
- testFactory.register();
-
- final NetworkCallback networkCallback;
- if (capability != NET_CAPABILITY_INTERNET) {
- // If the capability passed in argument is part of the default request, then the
- // factory will see the default request. Otherwise the filter will prevent the
- // factory from seeing it. In that case, add a request so it can be tested.
- assertFalse(testFactory.getMyStartRequested());
- NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
- networkCallback = new NetworkCallback();
- mCm.requestNetwork(request, networkCallback);
- } else {
- networkCallback = null;
- }
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
- assertTrue(testFactory.getMyStartRequested());
-
- // Now bring in a higher scored network.
- TestNetworkAgentWrapper testAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- // When testAgent connects, because of its score (50 legacy int / cell transport)
- // it will beat or equal the testFactory's offer, so the request will be removed.
- // Note the agent as validated only if the capability is INTERNET, as it's the only case
- // where it makes sense.
- testAgent.connect(NET_CAPABILITY_INTERNET == capability /* validated */);
- testAgent.addCapability(capability);
- testFactory.expectRequestRemove();
- testFactory.assertRequestCountEquals(0);
- assertFalse(testFactory.getMyStartRequested());
-
- // Add a request and make sure it's not sent to the factory, because the agent
- // is satisfying it better.
- final NetworkCallback cb = new ConnectivityManager.NetworkCallback();
- mCm.requestNetwork(new NetworkRequest.Builder().addCapability(capability).build(), cb);
- expectNoRequestChanged(testFactory);
- testFactory.assertRequestCountEquals(0);
- assertFalse(testFactory.getMyStartRequested());
-
- // If using legacy scores, make the test agent weak enough to have the exact same score as
- // the factory (50 for cell - 5 adjustment). Make sure the factory doesn't see the request.
- // If not using legacy score, this is a no-op and the "same score removes request" behavior
- // has already been tested above.
- testAgent.adjustScore(-5);
- expectNoRequestChanged(testFactory);
- assertFalse(testFactory.getMyStartRequested());
-
- // Make the test agent weak enough that the factory will see the two requests (the one that
- // was just sent, and either the default one or the one sent at the top of this test if
- // the default won't be seen).
- testAgent.setScore(new NetworkScore.Builder().setLegacyInt(2).setExiting(true).build());
- testFactory.expectRequestAdds(2);
- testFactory.assertRequestCountEquals(2);
- assertTrue(testFactory.getMyStartRequested());
-
- // Now unregister and make sure the request is removed.
- mCm.unregisterNetworkCallback(cb);
- testFactory.expectRequestRemove();
-
- // Bring in a bunch of requests.
- assertEquals(1, testFactory.getMyRequestCount());
- ConnectivityManager.NetworkCallback[] networkCallbacks =
- new ConnectivityManager.NetworkCallback[10];
- for (int i = 0; i< networkCallbacks.length; i++) {
- networkCallbacks[i] = new ConnectivityManager.NetworkCallback();
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(capability);
- mCm.requestNetwork(builder.build(), networkCallbacks[i]);
- }
- testFactory.expectRequestAdds(10);
- testFactory.assertRequestCountEquals(11); // +1 for the default/test specific request
- assertTrue(testFactory.getMyStartRequested());
-
- // Remove the requests.
- for (int i = 0; i < networkCallbacks.length; i++) {
- mCm.unregisterNetworkCallback(networkCallbacks[i]);
- }
- testFactory.expectRequestRemoves(10);
- testFactory.assertRequestCountEquals(1);
- assertTrue(testFactory.getMyStartRequested());
-
- // Adjust the agent score up again. Expect the request to be withdrawn.
- testAgent.setScore(new NetworkScore.Builder().setLegacyInt(50).build());
- testFactory.expectRequestRemove();
- testFactory.assertRequestCountEquals(0);
- assertFalse(testFactory.getMyStartRequested());
-
- // Drop the higher scored network.
- testAgent.disconnect();
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
- assertEquals(1, testFactory.getMyRequestCount());
- assertTrue(testFactory.getMyStartRequested());
-
- testFactory.terminate();
- if (networkCallback != null) mCm.unregisterNetworkCallback(networkCallback);
- handlerThread.quit();
- }
-
- @Test
- public void testNetworkFactoryRequests() throws Exception {
- tryNetworkFactoryRequests(NET_CAPABILITY_MMS);
- tryNetworkFactoryRequests(NET_CAPABILITY_SUPL);
- tryNetworkFactoryRequests(NET_CAPABILITY_DUN);
- tryNetworkFactoryRequests(NET_CAPABILITY_FOTA);
- tryNetworkFactoryRequests(NET_CAPABILITY_IMS);
- tryNetworkFactoryRequests(NET_CAPABILITY_CBS);
- tryNetworkFactoryRequests(NET_CAPABILITY_WIFI_P2P);
- tryNetworkFactoryRequests(NET_CAPABILITY_IA);
- tryNetworkFactoryRequests(NET_CAPABILITY_RCS);
- tryNetworkFactoryRequests(NET_CAPABILITY_XCAP);
- tryNetworkFactoryRequests(NET_CAPABILITY_ENTERPRISE);
- tryNetworkFactoryRequests(NET_CAPABILITY_EIMS);
- tryNetworkFactoryRequests(NET_CAPABILITY_NOT_METERED);
- tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET);
- tryNetworkFactoryRequests(NET_CAPABILITY_TRUSTED);
- tryNetworkFactoryRequests(NET_CAPABILITY_NOT_VPN);
- tryNetworkFactoryRequests(NET_CAPABILITY_VSIM);
- tryNetworkFactoryRequests(NET_CAPABILITY_BIP);
- // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
- }
-
- @Test
- public void testRegisterIgnoringScore() throws Exception {
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(90).build());
- mWiFiNetworkAgent.connect(true /* validated */);
-
- // Make sure the factory sees the default network
- final NetworkCapabilities filter = new NetworkCapabilities();
- filter.addTransportType(TRANSPORT_CELLULAR);
- filter.addCapability(NET_CAPABILITY_INTERNET);
- filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
- handlerThread.start();
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- testFactory.register();
-
- final MockNetworkFactory testFactoryAll = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactoryAll", filter, mCsHandlerThread);
- testFactoryAll.registerIgnoringScore();
-
- // The regular test factory should not see the request, because WiFi is stronger than cell.
- expectNoRequestChanged(testFactory);
- // With ignoringScore though the request is seen.
- testFactoryAll.expectRequestAdd();
-
- // The legacy int will be ignored anyway, set the only other knob to true
- mWiFiNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(110)
- .setTransportPrimary(true).build());
-
- expectNoRequestChanged(testFactory); // still not seeing the request
- expectNoRequestChanged(testFactoryAll); // still seeing the request
-
- mWiFiNetworkAgent.disconnect();
- }
-
- @Test
- public void testNetworkFactoryUnregister() throws Exception {
- // Make sure the factory sees the default network
- final NetworkCapabilities filter = new NetworkCapabilities();
- filter.addCapability(NET_CAPABILITY_INTERNET);
- filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
-
- final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
- handlerThread.start();
-
- // Checks that calling setScoreFilter on a NetworkFactory immediately before closing it
- // does not crash.
- for (int i = 0; i < 100; i++) {
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- // Register the factory and don't be surprised when the default request arrives.
- testFactory.register();
- testFactory.expectRequestAdd();
-
- testFactory.setScoreFilter(42);
- testFactory.terminate();
-
- if (i % 2 == 0) {
- try {
- testFactory.register();
- fail("Re-registering terminated NetworkFactory should throw");
- } catch (IllegalStateException expected) {
- }
- }
- }
- handlerThread.quit();
- }
-
- @Test
- public void testNoMutableNetworkRequests() throws Exception {
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
- NetworkRequest request1 = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED)
- .build();
- NetworkRequest request2 = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL)
- .build();
-
- Class<IllegalArgumentException> expected = IllegalArgumentException.class;
- assertThrows(expected, () -> mCm.requestNetwork(request1, new NetworkCallback()));
- assertThrows(expected, () -> mCm.requestNetwork(request1, pendingIntent));
- assertThrows(expected, () -> mCm.requestNetwork(request2, new NetworkCallback()));
- assertThrows(expected, () -> mCm.requestNetwork(request2, pendingIntent));
- }
-
- @Test
- public void testMMSonWiFi() throws Exception {
- // Test bringing up cellular without MMS NetworkRequest gets reaped
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- mCellNetworkAgent.connectWithoutInternet();
- mCellNetworkAgent.expectDisconnected();
- waitForIdle();
- assertEmpty(mCm.getAllNetworks());
- verifyNoNetwork();
-
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
-
- // Register MMS NetworkRequest
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(builder.build(), networkCallback);
-
- // Test bringing up unvalidated cellular with MMS
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- mCellNetworkAgent.connectWithoutInternet();
- networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- verifyActiveNetwork(TRANSPORT_WIFI);
-
- // Test releasing NetworkRequest disconnects cellular with MMS
- mCm.unregisterNetworkCallback(networkCallback);
- mCellNetworkAgent.expectDisconnected();
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testMMSonCell() throws Exception {
- // Test bringing up cellular without MMS
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- mCellNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
-
- // Register MMS NetworkRequest
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(builder.build(), networkCallback);
-
- // Test bringing up MMS cellular network
- TestNetworkAgentWrapper
- mmsNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- mmsNetworkAgent.connectWithoutInternet();
- networkCallback.expectAvailableCallbacksUnvalidated(mmsNetworkAgent);
- verifyActiveNetwork(TRANSPORT_CELLULAR);
-
- // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
- mCm.unregisterNetworkCallback(networkCallback);
- mmsNetworkAgent.expectDisconnected();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- }
-
- @Test
- public void testPartialConnectivity() throws Exception {
- // Register network callback.
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up validated mobile data.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- // Bring up wifi with partial connectivity.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithPartialConnectivity();
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
-
- // Mobile data should be the default network.
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- callback.assertNoCallback();
-
- // With HTTPS probe disabled, NetworkMonitor should pass the network validation with http
- // probe.
- mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */);
- // If the user chooses yes to use this partial connectivity wifi, switch the default
- // network to wifi and check if wifi becomes valid or not.
- mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
- false /* always */);
- // If user accepts partial connectivity network,
- // NetworkMonitor#setAcceptPartialConnectivity() should be called too.
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
-
- // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
- // validated.
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- NetworkCapabilities nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED,
- mWiFiNetworkAgent);
- assertTrue(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Disconnect and reconnect wifi with partial connectivity again.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithPartialConnectivity();
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
-
- // Mobile data should be the default network.
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // If the user chooses no, disconnect wifi immediately.
- mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), false/* accept */,
- false /* always */);
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // If user accepted partial connectivity before, and device reconnects to that network
- // again, but now the network has full connectivity. The network shouldn't contain
- // NET_CAPABILITY_PARTIAL_CONNECTIVITY.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- // acceptUnvalidated is also used as setting for accepting partial networks.
- mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
- true /* acceptUnvalidated */);
- mWiFiNetworkAgent.connect(true);
-
- // If user accepted partial connectivity network before,
- // NetworkMonitor#setAcceptPartialConnectivity() will be called in
- // ConnectivityService#updateNetworkInfo().
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertFalse(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
-
- // Wifi should be the default network.
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // The user accepted partial connectivity and selected "don't ask again". Now the user
- // reconnects to the partial connectivity network. Switch to wifi as soon as partial
- // connectivity is detected.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
- true /* acceptUnvalidated */);
- mWiFiNetworkAgent.connectWithPartialConnectivity();
- // If user accepted partial connectivity network before,
- // NetworkMonitor#setAcceptPartialConnectivity() will be called in
- // ConnectivityService#updateNetworkInfo().
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
- mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
-
- // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
- // validated.
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // If the user accepted partial connectivity, and the device auto-reconnects to the partial
- // connectivity network, it should contain both PARTIAL_CONNECTIVITY and VALIDATED.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(false /* explicitlySelected */,
- true /* acceptUnvalidated */);
-
- // NetworkMonitor will immediately (once the HTTPS probe fails...) report the network as
- // valid, because ConnectivityService calls setAcceptPartialConnectivity before it calls
- // notifyNetworkConnected.
- mWiFiNetworkAgent.connectWithPartialValidConnectivity(false /* isStrictMode */);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(
- NET_CAPABILITY_PARTIAL_CONNECTIVITY | NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- }
-
- @Test
- public void testCaptivePortalOnPartialConnectivity() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- // Bring up a network with a captive portal.
- // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String redirectUrl = "http://android.com/path";
- mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), redirectUrl);
-
- // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
- mCm.startCaptivePortalApp(mWiFiNetworkAgent.getNetwork());
- verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1))
- .launchCaptivePortalApp();
-
- // Report that the captive portal is dismissed with partial connectivity, and check that
- // callbacks are fired.
- mWiFiNetworkAgent.setNetworkPartial();
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- waitForIdle();
- captivePortalCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
- mWiFiNetworkAgent);
-
- // Report partial connectivity is accepted.
- mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */);
- mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
- false /* always */);
- waitForIdle();
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- NetworkCapabilities nc =
- validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
- mWiFiNetworkAgent);
-
- mCm.unregisterNetworkCallback(captivePortalCallback);
- mCm.unregisterNetworkCallback(validatedCallback);
- }
-
- @Test
- public void testCaptivePortal() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- // Bring up a network with a captive portal.
- // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String firstRedirectUrl = "http://example.com/firstPath";
- mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
-
- // Take down network.
- // Expect onLost callback.
- mWiFiNetworkAgent.disconnect();
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Bring up a network with a captive portal.
- // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String secondRedirectUrl = "http://example.com/secondPath";
- mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
-
- // Make captive portal disappear then revalidate.
- // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-
- // Break network connectivity.
- // Expect NET_CAPABILITY_VALIDATED onLost callback.
- mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
- validatedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- }
-
- @Test
- public void testCaptivePortalApp() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- // Bring up wifi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
-
- // Check that calling startCaptivePortalApp does nothing.
- final int fastTimeoutMs = 100;
- mCm.startCaptivePortalApp(wifiNetwork);
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor, never()).launchCaptivePortalApp();
- mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
-
- // Turn into a captive portal.
- mWiFiNetworkAgent.setNetworkPortal("http://example.com", false /* isStrictMode */);
- mCm.reportNetworkConnectivity(wifiNetwork, false);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- validatedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
- mCm.startCaptivePortalApp(wifiNetwork);
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor).launchCaptivePortalApp();
-
- // NetworkMonitor uses startCaptivePortal(Network, Bundle) (startCaptivePortalAppInternal)
- final Bundle testBundle = new Bundle();
- final String testKey = "testkey";
- final String testValue = "testvalue";
- testBundle.putString(testKey, testValue);
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_GRANTED);
- mCm.startCaptivePortalApp(wifiNetwork, testBundle);
- final Intent signInIntent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS);
- assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, signInIntent.getAction());
- assertEquals(testValue, signInIntent.getStringExtra(testKey));
-
- // Report that the captive portal is dismissed, and check that callbacks are fired
- mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- mCm.unregisterNetworkCallback(validatedCallback);
- mCm.unregisterNetworkCallback(captivePortalCallback);
- }
-
- @Test
- public void testAvoidOrIgnoreCaptivePortals() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID);
- // Bring up a network with a captive portal.
- // Expect it to fail to connect and not result in any callbacks.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String firstRedirectUrl = "http://example.com/firstPath";
-
- mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */);
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent.expectPreventReconnectReceived();
-
- assertNoCallbacks(captivePortalCallback, validatedCallback);
- }
-
- @Test
- public void testCaptivePortalApi() throws Exception {
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final String redirectUrl = "http://example.com/firstPath";
-
- mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- final CaptivePortalData testData = new CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse(redirectUrl))
- .setBytesRemaining(12345L)
- .build();
-
- mWiFiNetworkAgent.notifyCapportApiDataChanged(testData);
-
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> testData.equals(lp.getCaptivePortalData()));
-
- final LinkProperties newLps = new LinkProperties();
- newLps.setMtu(1234);
- mWiFiNetworkAgent.sendLinkProperties(newLps);
- // CaptivePortalData is not lost and unchanged when LPs are received from the NetworkAgent
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> testData.equals(lp.getCaptivePortalData()) && lp.getMtu() == 1234);
- }
-
- private TestNetworkCallback setupNetworkCallbackAndConnectToWifi() throws Exception {
- // Grant NETWORK_SETTINGS permission to be able to receive LinkProperties change callbacks
- // with sensitive (captive portal) data
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- mWiFiNetworkAgent.connectWithCaptivePortal(TEST_REDIRECT_URL, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- return captivePortalCallback;
- }
-
- private class CaptivePortalTestData {
- CaptivePortalTestData(CaptivePortalData naPasspointData, CaptivePortalData capportData,
- CaptivePortalData naOtherData, CaptivePortalData expectedMergedPasspointData,
- CaptivePortalData expectedMergedOtherData) {
- mNaPasspointData = naPasspointData;
- mCapportData = capportData;
- mNaOtherData = naOtherData;
- mExpectedMergedPasspointData = expectedMergedPasspointData;
- mExpectedMergedOtherData = expectedMergedOtherData;
- }
-
- public final CaptivePortalData mNaPasspointData;
- public final CaptivePortalData mCapportData;
- public final CaptivePortalData mNaOtherData;
- public final CaptivePortalData mExpectedMergedPasspointData;
- public final CaptivePortalData mExpectedMergedOtherData;
-
- }
-
- private CaptivePortalTestData setupCaptivePortalData() {
- final CaptivePortalData capportData = new CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_CAPPORT))
- .setUserPortalUrl(Uri.parse(TEST_USER_PORTAL_API_URL_CAPPORT))
- .setExpiryTime(1000000L)
- .setBytesRemaining(12345L)
- .build();
-
- final CaptivePortalData naPasspointData = new CaptivePortalData.Builder()
- .setBytesRemaining(80802L)
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_PASSPOINT),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
-
- final CaptivePortalData naOtherData = new CaptivePortalData.Builder()
- .setBytesRemaining(80802L)
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_OTHER),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER)
- .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_OTHER),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER)
- .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
-
- final CaptivePortalData expectedMergedPasspointData = new CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
- .setBytesRemaining(12345L)
- .setExpiryTime(1000000L)
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_PASSPOINT),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
-
- final CaptivePortalData expectedMergedOtherData = new CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
- .setBytesRemaining(12345L)
- .setExpiryTime(1000000L)
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_CAPPORT))
- .setUserPortalUrl(Uri.parse(TEST_USER_PORTAL_API_URL_CAPPORT))
- .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
- return new CaptivePortalTestData(naPasspointData, capportData, naOtherData,
- expectedMergedPasspointData, expectedMergedOtherData);
- }
-
- @Test
- public void testMergeCaptivePortalApiWithFriendlyNameAndVenueUrl() throws Exception {
- final TestNetworkCallback captivePortalCallback = setupNetworkCallbackAndConnectToWifi();
- final CaptivePortalTestData captivePortalTestData = setupCaptivePortalData();
-
- // Baseline capport data
- mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
-
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()));
-
- // Venue URL, T&C URL and friendly name from Network agent with Passpoint source, confirm
- // that API data gets precedence on the bytes remaining.
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
- mWiFiNetworkAgent.sendLinkProperties(linkProperties);
-
- // Make sure that the capport data is merged
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mExpectedMergedPasspointData
- .equals(lp.getCaptivePortalData()));
-
- // Now send this information from non-Passpoint source, confirm that Capport data takes
- // precedence
- linkProperties.setCaptivePortalData(captivePortalTestData.mNaOtherData);
- mWiFiNetworkAgent.sendLinkProperties(linkProperties);
-
- // Make sure that the capport data is merged
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mExpectedMergedOtherData
- .equals(lp.getCaptivePortalData()));
-
- // Create a new LP with no Network agent capport data
- final LinkProperties newLps = new LinkProperties();
- newLps.setMtu(1234);
- mWiFiNetworkAgent.sendLinkProperties(newLps);
- // CaptivePortalData is not lost and has the original values when LPs are received from the
- // NetworkAgent
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData())
- && lp.getMtu() == 1234);
-
- // Now send capport data only from the Network agent
- mWiFiNetworkAgent.notifyCapportApiDataChanged(null);
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> lp.getCaptivePortalData() == null);
-
- newLps.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
- mWiFiNetworkAgent.sendLinkProperties(newLps);
-
- // Make sure that only the network agent capport data is available
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData()));
- }
-
- @Test
- public void testMergeCaptivePortalDataFromNetworkAgentFirstThenCapport() throws Exception {
- final TestNetworkCallback captivePortalCallback = setupNetworkCallbackAndConnectToWifi();
- final CaptivePortalTestData captivePortalTestData = setupCaptivePortalData();
-
- // Venue URL and friendly name from Network agent, confirm that API data gets precedence
- // on the bytes remaining.
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
- mWiFiNetworkAgent.sendLinkProperties(linkProperties);
-
- // Make sure that the data is saved correctly
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData()));
-
- // Expected merged data: Network agent data is preferred, and values that are not used by
- // it are merged from capport data
- mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
-
- // Make sure that the Capport data is merged correctly
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mExpectedMergedPasspointData.equals(
- lp.getCaptivePortalData()));
-
- // Now set the naData to null
- linkProperties.setCaptivePortalData(null);
- mWiFiNetworkAgent.sendLinkProperties(linkProperties);
-
- // Make sure that the Capport data is retained correctly
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()));
- }
-
- @Test
- public void testMergeCaptivePortalDataFromNetworkAgentOtherSourceFirstThenCapport()
- throws Exception {
- final TestNetworkCallback captivePortalCallback = setupNetworkCallbackAndConnectToWifi();
- final CaptivePortalTestData captivePortalTestData = setupCaptivePortalData();
-
- // Venue URL and friendly name from Network agent, confirm that API data gets precedence
- // on the bytes remaining.
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setCaptivePortalData(captivePortalTestData.mNaOtherData);
- mWiFiNetworkAgent.sendLinkProperties(linkProperties);
-
- // Make sure that the data is saved correctly
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mNaOtherData.equals(lp.getCaptivePortalData()));
-
- // Expected merged data: Network agent data is preferred, and values that are not used by
- // it are merged from capport data
- mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
-
- // Make sure that the Capport data is merged correctly
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mExpectedMergedOtherData.equals(
- lp.getCaptivePortalData()));
- }
-
- private NetworkRequest.Builder newWifiRequestBuilder() {
- return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
- }
-
- /**
- * Verify request matching behavior with network specifiers.
- *
- * This test does not check updating the specifier on a live network because the specifier is
- * immutable and this triggers a WTF in
- * {@link ConnectivityService#mixInCapabilities(NetworkAgentInfo, NetworkCapabilities)}.
- */
- @Test
- public void testNetworkSpecifier() throws Exception {
- // A NetworkSpecifier subclass that matches all networks but must not be visible to apps.
- class ConfidentialMatchAllNetworkSpecifier extends NetworkSpecifier implements
- Parcelable {
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- return true;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {}
-
- @Override
- public NetworkSpecifier redact() {
- return null;
- }
- }
-
- // A network specifier that matches either another LocalNetworkSpecifier with the same
- // string or a ConfidentialMatchAllNetworkSpecifier, and can be passed to apps as is.
- class LocalStringNetworkSpecifier extends NetworkSpecifier implements Parcelable {
- private String mString;
-
- LocalStringNetworkSpecifier(String string) {
- mString = string;
- }
-
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- if (other instanceof LocalStringNetworkSpecifier) {
- return TextUtils.equals(mString,
- ((LocalStringNetworkSpecifier) other).mString);
- }
- if (other instanceof ConfidentialMatchAllNetworkSpecifier) return true;
- return false;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
- @Override
- public void writeToParcel(Parcel dest, int flags) {}
- }
-
-
- NetworkRequest rEmpty1 = newWifiRequestBuilder().build();
- NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build();
- NetworkRequest rEmpty3 = newWifiRequestBuilder().setNetworkSpecifier("").build();
- NetworkRequest rEmpty4 = newWifiRequestBuilder().setNetworkSpecifier(
- (NetworkSpecifier) null).build();
- NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier(
- new LocalStringNetworkSpecifier("foo")).build();
- NetworkRequest rBar = newWifiRequestBuilder().setNetworkSpecifier(
- new LocalStringNetworkSpecifier("bar")).build();
-
- TestNetworkCallback cEmpty1 = new TestNetworkCallback();
- TestNetworkCallback cEmpty2 = new TestNetworkCallback();
- TestNetworkCallback cEmpty3 = new TestNetworkCallback();
- TestNetworkCallback cEmpty4 = new TestNetworkCallback();
- TestNetworkCallback cFoo = new TestNetworkCallback();
- TestNetworkCallback cBar = new TestNetworkCallback();
- TestNetworkCallback[] emptyCallbacks = new TestNetworkCallback[] {
- cEmpty1, cEmpty2, cEmpty3, cEmpty4 };
-
- mCm.registerNetworkCallback(rEmpty1, cEmpty1);
- mCm.registerNetworkCallback(rEmpty2, cEmpty2);
- mCm.registerNetworkCallback(rEmpty3, cEmpty3);
- mCm.registerNetworkCallback(rEmpty4, cEmpty4);
- mCm.registerNetworkCallback(rFoo, cFoo);
- mCm.registerNetworkCallback(rBar, cBar);
-
- LocalStringNetworkSpecifier nsFoo = new LocalStringNetworkSpecifier("foo");
- LocalStringNetworkSpecifier nsBar = new LocalStringNetworkSpecifier("bar");
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, null /* specifier */,
- cEmpty1, cEmpty2, cEmpty3, cEmpty4);
- assertNoCallbacks(cFoo, cBar);
-
- mWiFiNetworkAgent.disconnect();
- expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.setNetworkSpecifier(nsFoo);
- mWiFiNetworkAgent.connect(false);
- expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, nsFoo,
- cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo);
- cBar.assertNoCallback();
- assertEquals(nsFoo,
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
- assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo);
-
- mWiFiNetworkAgent.disconnect();
- expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.setNetworkSpecifier(nsBar);
- mWiFiNetworkAgent.connect(false);
- expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, nsBar,
- cEmpty1, cEmpty2, cEmpty3, cEmpty4, cBar);
- cFoo.assertNoCallback();
- assertEquals(nsBar,
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
-
- mWiFiNetworkAgent.disconnect();
- expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cBar);
- cFoo.assertNoCallback();
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier());
- mWiFiNetworkAgent.connect(false);
- expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, null /* specifier */,
- cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
- assertNull(
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
-
- mWiFiNetworkAgent.disconnect();
- expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
- }
-
- /**
- * @return the context's attribution tag
- */
- private String getAttributionTag() {
- return mContext.getAttributionTag();
- }
-
- @Test
- public void testInvalidNetworkSpecifier() {
- assertThrows(IllegalArgumentException.class, () -> {
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- });
-
- assertThrows(IllegalArgumentException.class, () -> {
- NetworkCapabilities networkCapabilities = new NetworkCapabilities();
- networkCapabilities.addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(new MatchAllNetworkSpecifier());
- mService.requestNetwork(Process.INVALID_UID, networkCapabilities,
- NetworkRequest.Type.REQUEST.ordinal(), null, 0, null,
- ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
- mContext.getPackageName(), getAttributionTag());
- });
-
- class NonParcelableSpecifier extends NetworkSpecifier {
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- return false;
- }
- };
- class ParcelableSpecifier extends NonParcelableSpecifier implements Parcelable {
- @Override public int describeContents() { return 0; }
- @Override public void writeToParcel(Parcel p, int flags) {}
- }
-
- final NetworkRequest.Builder builder =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
- assertThrows(ClassCastException.class, () -> {
- builder.setNetworkSpecifier(new NonParcelableSpecifier());
- Parcel parcelW = Parcel.obtain();
- builder.build().writeToParcel(parcelW, 0);
- });
-
- final NetworkRequest nr =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET)
- .setNetworkSpecifier(new ParcelableSpecifier())
- .build();
- assertNotNull(nr);
-
- assertThrows(BadParcelableException.class, () -> {
- Parcel parcelW = Parcel.obtain();
- nr.writeToParcel(parcelW, 0);
- byte[] bytes = parcelW.marshall();
- parcelW.recycle();
-
- Parcel parcelR = Parcel.obtain();
- parcelR.unmarshall(bytes, 0, bytes.length);
- parcelR.setDataPosition(0);
- NetworkRequest rereadNr = NetworkRequest.CREATOR.createFromParcel(parcelR);
- });
- }
-
- @Test
- public void testNetworkRequestUidSpoofSecurityException() throws Exception {
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- NetworkRequest networkRequest = newWifiRequestBuilder().build();
- TestNetworkCallback networkCallback = new TestNetworkCallback();
- doThrow(new SecurityException()).when(mAppOpsManager).checkPackage(anyInt(), anyString());
- assertThrows(SecurityException.class, () -> {
- mCm.requestNetwork(networkRequest, networkCallback);
- });
- }
-
- @Test
- public void testInvalidSignalStrength() {
- NetworkRequest r = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_WIFI)
- .setSignalStrength(-75)
- .build();
- // Registering a NetworkCallback with signal strength but w/o NETWORK_SIGNAL_STRENGTH_WAKEUP
- // permission should get SecurityException.
- assertThrows(SecurityException.class, () ->
- mCm.registerNetworkCallback(r, new NetworkCallback()));
-
- assertThrows(SecurityException.class, () ->
- mCm.registerNetworkCallback(r, PendingIntent.getService(
- mServiceContext, 0 /* requestCode */, new Intent(), FLAG_IMMUTABLE)));
-
- // Requesting a Network with signal strength should get IllegalArgumentException.
- assertThrows(IllegalArgumentException.class, () ->
- mCm.requestNetwork(r, new NetworkCallback()));
-
- assertThrows(IllegalArgumentException.class, () ->
- mCm.requestNetwork(r, PendingIntent.getService(
- mServiceContext, 0 /* requestCode */, new Intent(), FLAG_IMMUTABLE)));
- }
-
- @Test
- public void testRegisterDefaultNetworkCallback() throws Exception {
- // NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
- defaultNetworkCallback.assertNoCallback();
-
- final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
- final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
- mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback, handler);
- systemDefaultCallback.assertNoCallback();
-
- // Create a TRANSPORT_CELLULAR request to keep the mobile interface up
- // whenever Wi-Fi is up. Without this, the mobile network agent is
- // reaped before any other activity can take place.
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
- cellNetworkCallback.assertNoCallback();
-
- // Bring up cell and expect CALLBACK_AVAILABLE.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- systemDefaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up wifi and expect CALLBACK_AVAILABLE.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- systemDefaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring down cell. Expect no default network callback, since it wasn't the default.
- mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultNetworkCallback.assertNoCallback();
- systemDefaultCallback.assertNoCallback();
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up cell. Expect no default network callback, since it won't be the default.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultNetworkCallback.assertNoCallback();
- systemDefaultCallback.assertNoCallback();
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring down wifi. Expect the default network callback to notified of LOST wifi
- // followed by AVAILABLE cell.
- mWiFiNetworkAgent.disconnect();
- cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- systemDefaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- systemDefaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
-
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- systemDefaultCallback.assertNoCallback();
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(null, systemDefaultCallback.getLastAvailableNetwork());
-
- mMockVpn.disconnect();
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- systemDefaultCallback.assertNoCallback();
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
- }
-
- @Test
- public void testAdditionalStateCallbacks() throws Exception {
- // File a network request for mobile.
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- // Bring up the mobile network.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- // We should get onAvailable(), onCapabilitiesChanged(), and
- // onLinkPropertiesChanged() in rapid succession. Additionally, we
- // should get onCapabilitiesChanged() when the mobile network validates.
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
-
- // Update LinkProperties.
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("foonet_data0");
- mCellNetworkAgent.sendLinkProperties(lp);
- // We should get onLinkPropertiesChanged().
- cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
-
- // Suspend the network.
- mCellNetworkAgent.suspend();
- cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED,
- mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertEquals(NetworkInfo.State.SUSPENDED, mCm.getActiveNetworkInfo().getState());
-
- // Register a garden variety default network request.
- TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
- // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
- // as well as onNetworkSuspended() in rapid succession.
- dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent, true);
- dfltNetworkCallback.assertNoCallback();
- mCm.unregisterNetworkCallback(dfltNetworkCallback);
-
- mCellNetworkAgent.resume();
- cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED,
- mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.RESUMED, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertEquals(NetworkInfo.State.CONNECTED, mCm.getActiveNetworkInfo().getState());
-
- dfltNetworkCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
- // This time onNetworkSuspended should not be called.
- dfltNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- dfltNetworkCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(dfltNetworkCallback);
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- }
-
- @Test
- public void testRegisterPrivilegedDefaultCallbacksRequireNetworkSettings() throws Exception {
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false /* validated */);
-
- final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
- final TestNetworkCallback callback = new TestNetworkCallback();
- assertThrows(SecurityException.class,
- () -> mCm.registerSystemDefaultNetworkCallback(callback, handler));
- callback.assertNoCallback();
- assertThrows(SecurityException.class,
- () -> mCm.registerDefaultNetworkCallbackForUid(APP1_UID, callback, handler));
- callback.assertNoCallback();
-
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
- mCm.registerSystemDefaultNetworkCallback(callback, handler);
- callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- mCm.unregisterNetworkCallback(callback);
-
- mCm.registerDefaultNetworkCallbackForUid(APP1_UID, callback, handler);
- callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- mCm.unregisterNetworkCallback(callback);
- }
-
- private void setCaptivePortalMode(int mode) {
- ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putInt(cr, ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE, mode);
- }
-
- private void setAlwaysOnNetworks(boolean enable) {
- ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putInt(cr, ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON,
- enable ? 1 : 0);
- mService.updateAlwaysOnNetworks();
- waitForIdle();
- }
-
- private void setPrivateDnsSettings(int mode, String specifier) {
- ConnectivitySettingsManager.setPrivateDnsMode(mServiceContext, mode);
- ConnectivitySettingsManager.setPrivateDnsHostname(mServiceContext, specifier);
- mService.updatePrivateDnsSettings();
- waitForIdle();
- }
-
- private boolean isForegroundNetwork(TestNetworkAgentWrapper network) {
- NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
- assertNotNull(nc);
- return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
- }
-
- @Test
- public void testBackgroundNetworks() throws Exception {
- // Create a cellular background request.
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- final TestNetworkCallback cellBgCallback = new TestNetworkCallback();
- mCm.requestBackgroundNetwork(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build(),
- cellBgCallback, mCsHandlerThread.getThreadHandler());
-
- // Make callbacks for monitoring.
- final NetworkRequest request = new NetworkRequest.Builder().build();
- final NetworkRequest fgRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_FOREGROUND).build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- final TestNetworkCallback fgCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
- mCm.registerNetworkCallback(fgRequest, fgCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
-
- // When wifi connects, cell lingers.
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- fgCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // When lingering is complete, cell is still there but is now in the background.
- waitForIdle();
- int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
- fgCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent, timeoutMs);
- // Expect a network capabilities update sans FOREGROUND.
- callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- assertFalse(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // File a cell request and check that cell comes into the foreground.
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- final TestNetworkCallback cellCallback = new TestNetworkCallback();
- mCm.requestNetwork(cellRequest, cellCallback);
- cellCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- // Expect a network capabilities update with FOREGROUND, because the most recent
- // request causes its state to change.
- cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // Release the request. The network immediately goes into the background, since it was not
- // lingering.
- mCm.unregisterNetworkCallback(cellCallback);
- fgCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- // Expect a network capabilities update sans FOREGROUND.
- callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- assertFalse(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // Disconnect wifi and check that cell is foreground again.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
-
- mCm.unregisterNetworkCallback(callback);
- mCm.unregisterNetworkCallback(fgCallback);
- mCm.unregisterNetworkCallback(cellBgCallback);
- }
-
- @Ignore // This test has instrinsic chances of spurious failures: ignore for continuous testing.
- public void benchmarkRequestRegistrationAndCallbackDispatch() throws Exception {
- // TODO: turn this unit test into a real benchmarking test.
- // Benchmarks connecting and switching performance in the presence of a large number of
- // NetworkRequests.
- // 1. File NUM_REQUESTS requests.
- // 2. Have a network connect. Wait for NUM_REQUESTS onAvailable callbacks to fire.
- // 3. Have a new network connect and outscore the previous. Wait for NUM_REQUESTS onLosing
- // and NUM_REQUESTS onAvailable callbacks to fire.
- // See how long it took.
- final int NUM_REQUESTS = 90;
- final int REGISTER_TIME_LIMIT_MS = 200;
- final int CONNECT_TIME_LIMIT_MS = 60;
- final int SWITCH_TIME_LIMIT_MS = 60;
- final int UNREGISTER_TIME_LIMIT_MS = 20;
-
- final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
- final NetworkCallback[] callbacks = new NetworkCallback[NUM_REQUESTS];
- final CountDownLatch availableLatch = new CountDownLatch(NUM_REQUESTS);
- final CountDownLatch losingLatch = new CountDownLatch(NUM_REQUESTS);
-
- for (int i = 0; i < NUM_REQUESTS; i++) {
- callbacks[i] = new NetworkCallback() {
- @Override public void onAvailable(Network n) { availableLatch.countDown(); }
- @Override public void onLosing(Network n, int t) { losingLatch.countDown(); }
- };
- }
-
- assertRunsInAtMost("Registering callbacks", REGISTER_TIME_LIMIT_MS, () -> {
- for (NetworkCallback cb : callbacks) {
- mCm.registerNetworkCallback(request, cb);
- }
- });
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- // Don't request that the network validate, because otherwise connect() will block until
- // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired,
- // and we won't actually measure anything.
- mCellNetworkAgent.connect(false);
-
- long onAvailableDispatchingDuration = durationOf(() -> {
- await(availableLatch, 10 * CONNECT_TIME_LIMIT_MS);
- });
- Log.d(TAG, String.format("Dispatched %d of %d onAvailable callbacks in %dms",
- NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS,
- onAvailableDispatchingDuration));
- assertTrue(String.format("Dispatching %d onAvailable callbacks in %dms, expected %dms",
- NUM_REQUESTS, onAvailableDispatchingDuration, CONNECT_TIME_LIMIT_MS),
- onAvailableDispatchingDuration <= CONNECT_TIME_LIMIT_MS);
-
- // Give wifi a high enough score that we'll linger cell when wifi comes up.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.adjustScore(40);
- mWiFiNetworkAgent.connect(false);
-
- long onLostDispatchingDuration = durationOf(() -> {
- await(losingLatch, 10 * SWITCH_TIME_LIMIT_MS);
- });
- Log.d(TAG, String.format("Dispatched %d of %d onLosing callbacks in %dms",
- NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, onLostDispatchingDuration));
- assertTrue(String.format("Dispatching %d onLosing callbacks in %dms, expected %dms",
- NUM_REQUESTS, onLostDispatchingDuration, SWITCH_TIME_LIMIT_MS),
- onLostDispatchingDuration <= SWITCH_TIME_LIMIT_MS);
-
- assertRunsInAtMost("Unregistering callbacks", UNREGISTER_TIME_LIMIT_MS, () -> {
- for (NetworkCallback cb : callbacks) {
- mCm.unregisterNetworkCallback(cb);
- }
- });
- }
-
- @Test
- public void testMobileDataAlwaysOn() throws Exception {
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
-
- final HandlerThread handlerThread = new HandlerThread("MobileDataAlwaysOnFactory");
- handlerThread.start();
- NetworkCapabilities filter = new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .addCapability(NET_CAPABILITY_INTERNET);
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- testFactory.setScoreFilter(40);
-
- // Register the factory and expect it to start looking for a network.
- testFactory.register();
-
- try {
- // Expect the factory to receive the default network request.
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
- assertTrue(testFactory.getMyStartRequested());
-
- // Bring up wifi. The factory stops looking for a network.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- // Score 60 - 40 penalty for not validated yet, then 60 when it validates
- mWiFiNetworkAgent.connect(true);
- // The network connects with a low score, so the offer can still beat it and
- // nothing happens. Then the network validates, and the offer with its filter score
- // of 40 can no longer beat it and the request is removed.
- testFactory.expectRequestRemove();
- testFactory.assertRequestCountEquals(0);
-
- assertFalse(testFactory.getMyStartRequested());
-
- // Turn on mobile data always on. This request will not match the wifi request, so
- // it will be sent to the test factory whose filters allow to see it.
- setAlwaysOnNetworks(true);
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
-
- assertTrue(testFactory.getMyStartRequested());
-
- // Bring up cell data and check that the factory stops looking.
- assertLength(1, mCm.getAllNetworks());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent, false, false, false,
- TEST_CALLBACK_TIMEOUT_MS);
- // When cell connects, it will satisfy the "mobile always on request" right away
- // by virtue of being the only network that can satisfy the request. However, its
- // score is low (50 - 40 = 10) so the test factory can still hope to beat it.
- expectNoRequestChanged(testFactory);
-
- // Next, cell validates. This gives it a score of 50 and the test factory can't
- // hope to beat that according to its filters. It will see the message that its
- // offer is now unnecessary.
- mCellNetworkAgent.setNetworkValid(true);
- // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
- // validated – see testPartialConnectivity.
- mCm.reportNetworkConnectivity(mCellNetworkAgent.getNetwork(), true);
- cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent);
- testFactory.expectRequestRemove();
- testFactory.assertRequestCountEquals(0);
- // Accordingly, the factory shouldn't be started.
- assertFalse(testFactory.getMyStartRequested());
-
- // Check that cell data stays up.
- waitForIdle();
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertLength(2, mCm.getAllNetworks());
-
- // Cell disconnects. There is still the "mobile data always on" request outstanding,
- // and the test factory should see it now that it isn't hopelessly outscored.
- mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- assertLength(1, mCm.getAllNetworks());
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
-
- // Reconnect cell validated, see the request disappear again. Then withdraw the
- // mobile always on request. This will tear down cell, and there shouldn't be a
- // blip where the test factory briefly sees the request or anything.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertLength(2, mCm.getAllNetworks());
- testFactory.expectRequestRemove();
- testFactory.assertRequestCountEquals(0);
- setAlwaysOnNetworks(false);
- expectNoRequestChanged(testFactory);
- testFactory.assertRequestCountEquals(0);
- assertFalse(testFactory.getMyStartRequested());
- // ... and cell data to be torn down immediately since it is no longer nascent.
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertLength(1, mCm.getAllNetworks());
- } finally {
- testFactory.terminate();
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- handlerThread.quit();
- }
- }
-
- @Test
- public void testAvoidBadWifiSetting() throws Exception {
- final ContentResolver cr = mServiceContext.getContentResolver();
- final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
-
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
- String[] values = new String[] {null, "0", "1"};
- for (int i = 0; i < values.length; i++) {
- Settings.Global.putInt(cr, settingName, 1);
- mPolicyTracker.reevaluate();
- waitForIdle();
- String msg = String.format("config=false, setting=%s", values[i]);
- assertTrue(mService.avoidBadWifi());
- assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated());
- }
-
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
-
- Settings.Global.putInt(cr, settingName, 0);
- mPolicyTracker.reevaluate();
- waitForIdle();
- assertFalse(mService.avoidBadWifi());
- assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
-
- Settings.Global.putInt(cr, settingName, 1);
- mPolicyTracker.reevaluate();
- waitForIdle();
- assertTrue(mService.avoidBadWifi());
- assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
-
- Settings.Global.putString(cr, settingName, null);
- mPolicyTracker.reevaluate();
- waitForIdle();
- assertFalse(mService.avoidBadWifi());
- assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated());
- }
-
- @Ignore("Refactoring in progress b/178071397")
- @Test
- public void testAvoidBadWifi() throws Exception {
- final ContentResolver cr = mServiceContext.getContentResolver();
-
- // Pretend we're on a carrier that restricts switching away from bad wifi.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
-
- // File a request for cell to ensure it doesn't go down.
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- NetworkRequest validatedWifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_VALIDATED)
- .build();
- TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
-
- Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 0);
- mPolicyTracker.reevaluate();
-
- // Bring up validated cell.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- Network cellNetwork = mCellNetworkAgent.getNetwork();
-
- // Bring up validated wifi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
-
- // Fail validation on wifi.
- mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(wifiNetwork, false);
- defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Because avoid bad wifi is off, we don't switch to cellular.
- defaultCallback.assertNoCallback();
- assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertEquals(mCm.getActiveNetwork(), wifiNetwork);
-
- // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
- // that we switch back to cell.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // Switch back to a restrictive carrier.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), wifiNetwork);
-
- // Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
- mCm.setAvoidUnvalidated(wifiNetwork);
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // Disconnect and reconnect wifi to clear the one-time switch above.
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- wifiNetwork = mWiFiNetworkAgent.getNetwork();
-
- // Fail validation on wifi and expect the dialog to appear.
- mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(wifiNetwork, false);
- defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Simulate the user selecting "switch" and checking the don't ask again checkbox.
- Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1);
- mPolicyTracker.reevaluate();
-
- // We now switch to cell.
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // Simulate the user turning the cellular fallback setting off and then on.
- // We switch to wifi and then to cell.
- Settings.Global.putString(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, null);
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), wifiNetwork);
- Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1);
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // If cell goes down, we switch to wifi.
- mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- validatedWifiCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- mCm.unregisterNetworkCallback(validatedWifiCallback);
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- @Test
- public void testMeteredMultipathPreferenceSetting() throws Exception {
- final ContentResolver cr = mServiceContext.getContentResolver();
- final String settingName = ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
-
- for (int config : Arrays.asList(0, 3, 2)) {
- for (String setting: Arrays.asList(null, "0", "2", "1")) {
- mPolicyTracker.mConfigMeteredMultipathPreference = config;
- Settings.Global.putString(cr, settingName, setting);
- mPolicyTracker.reevaluate();
- waitForIdle();
-
- final int expected = (setting != null) ? Integer.parseInt(setting) : config;
- String msg = String.format("config=%d, setting=%s", config, setting);
- assertEquals(msg, expected, mCm.getMultipathPreference(null));
- }
- }
- }
-
- /**
- * Validate that a satisfied network request does not trigger onUnavailable() once the
- * time-out period expires.
- */
- @Test
- public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
- TEST_CALLBACK_TIMEOUT_MS);
-
- // pass timeout and validate that UNAVAILABLE is not called
- networkCallback.assertNoCallback();
- }
-
- /**
- * Validate that a satisfied network request followed by a disconnected (lost) network does
- * not trigger onUnavailable() once the time-out period expires.
- */
- @Test
- public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
- TEST_CALLBACK_TIMEOUT_MS);
- mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Validate that UNAVAILABLE is not called
- networkCallback.assertNoCallback();
- }
-
- /**
- * Validate that when a time-out is specified for a network request the onUnavailable()
- * callback is called when time-out expires. Then validate that if network request is
- * (somehow) satisfied - the callback isn't called later.
- */
- @Test
- public void testTimedoutNetworkRequest() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final int timeoutMs = 10;
- mCm.requestNetwork(nr, networkCallback, timeoutMs);
-
- // pass timeout and validate that UNAVAILABLE is called
- networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
-
- // create a network satisfying request - validate that request not triggered
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.assertNoCallback();
- }
-
- /**
- * Validate that when a network request is unregistered (cancelled), no posterior event can
- * trigger the callback.
- */
- @Test
- public void testNoCallbackAfterUnregisteredNetworkRequest() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final int timeoutMs = 10;
-
- mCm.requestNetwork(nr, networkCallback, timeoutMs);
- mCm.unregisterNetworkCallback(networkCallback);
- // Regardless of the timeout, unregistering the callback in ConnectivityManager ensures
- // that this callback will not be called.
- networkCallback.assertNoCallback();
-
- // create a network satisfying request - validate that request not triggered
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.assertNoCallback();
- }
-
- @Test
- public void testUnfulfillableNetworkRequest() throws Exception {
- runUnfulfillableNetworkRequest(false);
- }
-
- @Test
- public void testUnfulfillableNetworkRequestAfterUnregister() throws Exception {
- runUnfulfillableNetworkRequest(true);
- }
-
- /**
- * Validate the callback flow for a factory releasing a request as unfulfillable.
- */
- private void runUnfulfillableNetworkRequest(boolean preUnregister) throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
-
- final HandlerThread handlerThread = new HandlerThread("testUnfulfillableNetworkRequest");
- handlerThread.start();
- NetworkCapabilities filter = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- testFactory.setScoreFilter(40);
-
- // Register the factory and expect it to receive the default request.
- testFactory.register();
- testFactory.expectRequestAdd();
-
- try {
- // Now file the test request and expect it.
- mCm.requestNetwork(nr, networkCallback);
- final NetworkRequest newRequest = testFactory.expectRequestAdd().request;
-
- if (preUnregister) {
- mCm.unregisterNetworkCallback(networkCallback);
-
- // The request has been released : the factory should see it removed
- // immediately.
- testFactory.expectRequestRemove();
-
- // Simulate the factory releasing the request as unfulfillable: no-op since
- // the callback has already been unregistered (but a test that no exceptions are
- // thrown).
- testFactory.triggerUnfulfillable(newRequest);
- } else {
- // Simulate the factory releasing the request as unfulfillable and expect
- // onUnavailable!
- testFactory.triggerUnfulfillable(newRequest);
-
- networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
-
- // Declaring a request unfulfillable releases it automatically.
- testFactory.expectRequestRemove();
-
- // unregister network callback - a no-op (since already freed by the
- // on-unavailable), but should not fail or throw exceptions.
- mCm.unregisterNetworkCallback(networkCallback);
-
- // The factory should not see any further removal, as this request has
- // already been removed.
- }
- } finally {
- testFactory.terminate();
- handlerThread.quit();
- }
- }
-
- private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
-
- public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }
-
- private class CallbackValue {
- public CallbackType callbackType;
- public int error;
-
- public CallbackValue(CallbackType type) {
- this.callbackType = type;
- this.error = PacketKeepalive.SUCCESS;
- assertTrue("onError callback must have error", type != CallbackType.ON_ERROR);
- }
-
- public CallbackValue(CallbackType type, int error) {
- this.callbackType = type;
- this.error = error;
- assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR);
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof CallbackValue &&
- this.callbackType == ((CallbackValue) o).callbackType &&
- this.error == ((CallbackValue) o).error;
- }
-
- @Override
- public String toString() {
- return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error);
- }
- }
-
- private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
-
- @Override
- public void onStarted() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- @Override
- public void onStopped() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- @Override
- public void onError(int error) {
- mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
- }
-
- private void expectCallback(CallbackValue callbackValue) throws InterruptedException {
- assertEquals(callbackValue, mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- }
-
- public void expectStarted() throws Exception {
- expectCallback(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- public void expectStopped() throws Exception {
- expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- public void expectError(int error) throws Exception {
- expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
- }
- }
-
- private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback {
-
- public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
-
- private class CallbackValue {
- public CallbackType callbackType;
- public int error;
-
- CallbackValue(CallbackType type) {
- this.callbackType = type;
- this.error = SocketKeepalive.SUCCESS;
- assertTrue("onError callback must have error", type != CallbackType.ON_ERROR);
- }
-
- CallbackValue(CallbackType type, int error) {
- this.callbackType = type;
- this.error = error;
- assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR);
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof CallbackValue
- && this.callbackType == ((CallbackValue) o).callbackType
- && this.error == ((CallbackValue) o).error;
- }
-
- @Override
- public String toString() {
- return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType,
- error);
- }
- }
-
- private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
- private final Executor mExecutor;
-
- TestSocketKeepaliveCallback(@NonNull Executor executor) {
- mExecutor = executor;
- }
-
- @Override
- public void onStarted() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- @Override
- public void onStopped() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- @Override
- public void onError(int error) {
- mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
- }
-
- private void expectCallback(CallbackValue callbackValue) throws InterruptedException {
- assertEquals(callbackValue, mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- }
-
- public void expectStarted() throws InterruptedException {
- expectCallback(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- public void expectStopped() throws InterruptedException {
- expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- public void expectError(int error) throws InterruptedException {
- expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
- }
-
- public void assertNoCallback() {
- waitForIdleSerialExecutor(mExecutor, TIMEOUT_MS);
- CallbackValue cv = mCallbacks.peek();
- assertNull("Unexpected callback: " + cv, cv);
- }
- }
-
- private Network connectKeepaliveNetwork(LinkProperties lp) throws Exception {
- // Ensure the network is disconnected before anything else occurs
- if (mWiFiNetworkAgent != null) {
- assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
- }
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- waitForIdle();
- return mWiFiNetworkAgent.getNetwork();
- }
-
- @Test
- public void testPacketKeepalives() throws Exception {
- InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
- InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
- InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
- InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
- InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
-
- final int validKaInterval = 15;
- final int invalidKaInterval = 9;
-
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv6, 64));
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
-
- Network notMyNet = new Network(61234);
- Network myNet = connectKeepaliveNetwork(lp);
-
- TestKeepaliveCallback callback = new TestKeepaliveCallback();
- PacketKeepalive ka;
-
- // Attempt to start keepalives with invalid parameters and check for errors.
- ka = mCm.startNattKeepalive(notMyNet, validKaInterval, callback, myIPv4, 1234, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
-
- ka = mCm.startNattKeepalive(myNet, invalidKaInterval, callback, myIPv4, 1234, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_INTERVAL);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 1234, dstIPv6);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
-
- // NAT-T is only supported for IPv4.
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv6);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
-
- // Check that a started keepalive can be stopped.
- mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
- mWiFiNetworkAgent.setStopKeepaliveEvent(PacketKeepalive.SUCCESS);
- ka.stop();
- callback.expectStopped();
-
- // Check that deleting the IP address stops the keepalive.
- LinkProperties bogusLp = new LinkProperties(lp);
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
- bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
- bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
- mWiFiNetworkAgent.sendLinkProperties(bogusLp);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
- mWiFiNetworkAgent.sendLinkProperties(lp);
-
- // Check that a started keepalive is stopped correctly when the network disconnects.
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
-
- // ... and that stopping it after that has no adverse effects.
- waitForIdle();
- final Network myNetAlias = myNet;
- assertNull(mCm.getNetworkCapabilities(myNetAlias));
- ka.stop();
-
- // Reconnect.
- myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
-
- // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
-
- // The second one gets slot 2.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
- TestKeepaliveCallback callback2 = new TestKeepaliveCallback();
- PacketKeepalive ka2 = mCm.startNattKeepalive(
- myNet, validKaInterval, callback2, myIPv4, 6789, dstIPv4);
- callback2.expectStarted();
-
- // Now stop the first one and create a third. This also gets slot 1.
- ka.stop();
- callback.expectStopped();
-
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
- TestKeepaliveCallback callback3 = new TestKeepaliveCallback();
- PacketKeepalive ka3 = mCm.startNattKeepalive(
- myNet, validKaInterval, callback3, myIPv4, 9876, dstIPv4);
- callback3.expectStarted();
-
- ka2.stop();
- callback2.expectStopped();
-
- ka3.stop();
- callback3.expectStopped();
- }
-
- // Helper method to prepare the executor and run test
- private void runTestWithSerialExecutors(ExceptionUtils.ThrowingConsumer<Executor> functor)
- throws Exception {
- final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor();
- final Executor executorInline = (Runnable r) -> r.run();
- functor.accept(executorSingleThread);
- executorSingleThread.shutdown();
- functor.accept(executorInline);
- }
-
- @Test
- public void testNattSocketKeepalives() throws Exception {
- runTestWithSerialExecutors(executor -> doTestNattSocketKeepalivesWithExecutor(executor));
- runTestWithSerialExecutors(executor -> doTestNattSocketKeepalivesFdWithExecutor(executor));
- }
-
- private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception {
- // TODO: 1. Move this outside of ConnectivityServiceTest.
- // 2. Make test to verify that Nat-T keepalive socket is created by IpSecService.
- // 3. Mock ipsec service.
- final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
- final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
- final InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
- final InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
- final InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
-
- final int validKaInterval = 15;
- final int invalidKaInterval = 9;
-
- final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
- final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket();
- final int srcPort = testSocket.getPort();
-
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv6, 64));
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
-
- Network notMyNet = new Network(61234);
- Network myNet = connectKeepaliveNetwork(lp);
-
- TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
-
- // Attempt to start keepalives with invalid parameters and check for errors.
- // Invalid network.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- notMyNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
- }
-
- // Invalid interval.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(invalidKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_INTERVAL);
- }
-
- // Invalid destination.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- }
-
- // Invalid source;
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv6, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- }
-
- // NAT-T is only supported for IPv4.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv6, dstIPv6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- }
-
- // Basic check before testing started keepalive.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_UNSUPPORTED);
- }
-
- // Check that a started keepalive can be stopped.
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
- ka.stop();
- callback.expectStopped();
-
- // Check that keepalive could be restarted.
- ka.start(validKaInterval);
- callback.expectStarted();
- ka.stop();
- callback.expectStopped();
-
- // Check that keepalive can be restarted without waiting for callback.
- ka.start(validKaInterval);
- callback.expectStarted();
- ka.stop();
- ka.start(validKaInterval);
- callback.expectStopped();
- callback.expectStarted();
- ka.stop();
- callback.expectStopped();
- }
-
- // Check that deleting the IP address stops the keepalive.
- LinkProperties bogusLp = new LinkProperties(lp);
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
- bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
- mWiFiNetworkAgent.sendLinkProperties(bogusLp);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- }
-
- // Check that a started keepalive is stopped correctly when the network disconnects.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
-
- // ... and that stopping it after that has no adverse effects.
- waitForIdle();
- final Network myNetAlias = myNet;
- assertNull(mCm.getNetworkCapabilities(myNetAlias));
- ka.stop();
- callback.assertNoCallback();
- }
-
- // Reconnect.
- myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
-
- // Check that a stop followed by network disconnects does not result in crash.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- // Delay the response of keepalive events in networkAgent long enough to make sure
- // the follow-up network disconnection will be processed first.
- mWiFiNetworkAgent.setKeepaliveResponseDelay(3 * TIMEOUT_MS);
- ka.stop();
-
- // Make sure the stop has been processed. Wait for executor idle is needed to prevent
- // flaky since the actual stop call to the service is delegated to executor thread.
- waitForIdleSerialExecutor(executor, TIMEOUT_MS);
- waitForIdle();
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- callback.expectStopped();
- callback.assertNoCallback();
- }
-
- // Reconnect.
- waitForIdle();
- myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
-
- // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
- int srcPort2 = 0;
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
-
- // The second one gets slot 2.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
- final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket();
- srcPort2 = testSocket2.getPort();
- TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback(executor);
- try (SocketKeepalive ka2 = mCm.createSocketKeepalive(
- myNet, testSocket2, myIPv4, dstIPv4, executor, callback2)) {
- ka2.start(validKaInterval);
- callback2.expectStarted();
-
- ka.stop();
- callback.expectStopped();
-
- ka2.stop();
- callback2.expectStopped();
-
- testSocket.close();
- testSocket2.close();
- }
- }
-
- // Check that there is no port leaked after all keepalives and sockets are closed.
- // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7.
- // assertFalse(isUdpPortInUse(srcPort));
- // assertFalse(isUdpPortInUse(srcPort2));
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent = null;
- }
-
- @Test
- public void testTcpSocketKeepalives() throws Exception {
- runTestWithSerialExecutors(executor -> doTestTcpSocketKeepalivesWithExecutor(executor));
- }
-
- private void doTestTcpSocketKeepalivesWithExecutor(Executor executor) throws Exception {
- final int srcPortV4 = 12345;
- final int srcPortV6 = 23456;
- final InetAddress myIPv4 = InetAddress.getByName("127.0.0.1");
- final InetAddress myIPv6 = InetAddress.getByName("::1");
-
- final int validKaInterval = 15;
-
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv6, 64));
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- lp.addRoute(new RouteInfo(InetAddress.getByName("127.0.0.254")));
-
- final Network notMyNet = new Network(61234);
- final Network myNet = connectKeepaliveNetwork(lp);
-
- final Socket testSocketV4 = new Socket();
- final Socket testSocketV6 = new Socket();
-
- TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
-
- // Attempt to start Tcp keepalives with invalid parameters and check for errors.
- // Invalid network.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- notMyNet, testSocketV4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
- }
-
- // Invalid Socket (socket is not bound with IPv4 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- // Invalid Socket (socket is not bound with IPv6 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- // Bind the socket address
- testSocketV4.bind(new InetSocketAddress(myIPv4, srcPortV4));
- testSocketV6.bind(new InetSocketAddress(myIPv6, srcPortV6));
-
- // Invalid Socket (socket is bound with IPv4 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- // Invalid Socket (socket is bound with IPv6 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- testSocketV4.close();
- testSocketV6.close();
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent = null;
- }
-
- private void doTestNattSocketKeepalivesFdWithExecutor(Executor executor) throws Exception {
- final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
- final InetAddress anyIPv4 = InetAddress.getByName("0.0.0.0");
- final InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
- final int validKaInterval = 15;
-
- // Prepare the target network.
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
- Network myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
- mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
-
- TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
-
- // Prepare the target file descriptor, keep only one instance.
- final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
- final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket();
- final int srcPort = testSocket.getPort();
- final ParcelFileDescriptor testPfd =
- ParcelFileDescriptor.dup(testSocket.getFileDescriptor());
- testSocket.close();
- assertTrue(isUdpPortInUse(srcPort));
-
- // Start keepalive and explicit make the variable goes out of scope with try-with-resources
- // block.
- try (SocketKeepalive ka = mCm.createNattKeepalive(
- myNet, testPfd, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- ka.stop();
- callback.expectStopped();
- }
-
- // Check that the ParcelFileDescriptor is still valid after keepalive stopped,
- // ErrnoException with EBADF will be thrown if the socket is closed when checking local
- // address.
- assertTrue(isUdpPortInUse(srcPort));
- final InetSocketAddress sa =
- (InetSocketAddress) Os.getsockname(testPfd.getFileDescriptor());
- assertEquals(anyIPv4, sa.getAddress());
-
- testPfd.close();
- // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7.
- // assertFalse(isUdpPortInUse(srcPort));
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent = null;
- }
-
- private static boolean isUdpPortInUse(int port) {
- try (DatagramSocket ignored = new DatagramSocket(port)) {
- return false;
- } catch (IOException alreadyInUse) {
- return true;
- }
- }
-
- @Test
- public void testGetCaptivePortalServerUrl() throws Exception {
- String url = mCm.getCaptivePortalServerUrl();
- assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
- }
-
- private static class TestNetworkPinner extends NetworkPinner {
- public static boolean awaitPin(int timeoutMs) throws InterruptedException {
- synchronized(sLock) {
- if (sNetwork == null) {
- sLock.wait(timeoutMs);
- }
- return sNetwork != null;
- }
- }
-
- public static boolean awaitUnpin(int timeoutMs) throws InterruptedException {
- synchronized(sLock) {
- if (sNetwork != null) {
- sLock.wait(timeoutMs);
- }
- return sNetwork == null;
- }
- }
- }
-
- private void assertPinnedToWifiWithCellDefault() {
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- }
-
- private void assertPinnedToWifiWithWifiDefault() {
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- }
-
- private void assertNotPinnedToWifi() {
- assertNull(mCm.getBoundNetworkForProcess());
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- }
-
- @Test
- public void testNetworkPinner() throws Exception {
- NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .build();
- assertNull(mCm.getBoundNetworkForProcess());
-
- TestNetworkPinner.pin(mServiceContext, wifiRequest);
- assertNull(mCm.getBoundNetworkForProcess());
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
-
- // When wi-fi connects, expect to be pinned.
- assertTrue(TestNetworkPinner.awaitPin(100));
- assertPinnedToWifiWithCellDefault();
-
- // Disconnect and expect the pin to drop.
- mWiFiNetworkAgent.disconnect();
- assertTrue(TestNetworkPinner.awaitUnpin(100));
- assertNotPinnedToWifi();
-
- // Reconnecting does not cause the pin to come back.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- assertFalse(TestNetworkPinner.awaitPin(100));
- assertNotPinnedToWifi();
-
- // Pinning while connected causes the pin to take effect immediately.
- TestNetworkPinner.pin(mServiceContext, wifiRequest);
- assertTrue(TestNetworkPinner.awaitPin(100));
- assertPinnedToWifiWithCellDefault();
-
- // Explicitly unpin and expect to use the default network again.
- TestNetworkPinner.unpin();
- assertNotPinnedToWifi();
-
- // Disconnect cell and wifi.
- ExpectedBroadcast b = registerConnectivityBroadcast(3); // cell down, wifi up, wifi down.
- mCellNetworkAgent.disconnect();
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
-
- // Pinning takes effect even if the pinned network is the default when the pin is set...
- TestNetworkPinner.pin(mServiceContext, wifiRequest);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- assertTrue(TestNetworkPinner.awaitPin(100));
- assertPinnedToWifiWithWifiDefault();
-
- // ... and is maintained even when that network is no longer the default.
- b = registerConnectivityBroadcast(1);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- assertPinnedToWifiWithCellDefault();
- }
-
- @Test
- public void testNetworkCallbackMaximum() throws Exception {
- final int MAX_REQUESTS = 100;
- final int CALLBACKS = 89;
- final int INTENTS = 11;
- final int SYSTEM_ONLY_MAX_REQUESTS = 250;
- assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
-
- NetworkRequest networkRequest = new NetworkRequest.Builder().build();
- ArrayList<Object> registered = new ArrayList<>();
-
- int j = 0;
- while (j++ < CALLBACKS / 2) {
- NetworkCallback cb = new NetworkCallback();
- mCm.requestNetwork(networkRequest, cb);
- registered.add(cb);
- }
- while (j++ < CALLBACKS) {
- NetworkCallback cb = new NetworkCallback();
- mCm.registerNetworkCallback(networkRequest, cb);
- registered.add(cb);
- }
- j = 0;
- while (j++ < INTENTS / 2) {
- final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("a" + j), FLAG_IMMUTABLE);
- mCm.requestNetwork(networkRequest, pi);
- registered.add(pi);
- }
- while (j++ < INTENTS) {
- final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("b" + j), FLAG_IMMUTABLE);
- mCm.registerNetworkCallback(networkRequest, pi);
- registered.add(pi);
- }
-
- // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
- assertThrows(TooManyRequestsException.class, () ->
- mCm.requestNetwork(networkRequest, new NetworkCallback())
- );
- assertThrows(TooManyRequestsException.class, () ->
- mCm.registerNetworkCallback(networkRequest, new NetworkCallback())
- );
- assertThrows(TooManyRequestsException.class, () ->
- mCm.requestNetwork(networkRequest,
- PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("c"), FLAG_IMMUTABLE))
- );
- assertThrows(TooManyRequestsException.class, () ->
- mCm.registerNetworkCallback(networkRequest,
- PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("d"), FLAG_IMMUTABLE))
- );
-
- // The system gets another SYSTEM_ONLY_MAX_REQUESTS slots.
- final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
- withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
- ArrayList<NetworkCallback> systemRegistered = new ArrayList<>();
- for (int i = 0; i < SYSTEM_ONLY_MAX_REQUESTS - 1; i++) {
- NetworkCallback cb = new NetworkCallback();
- if (i % 2 == 0) {
- mCm.registerDefaultNetworkCallbackForUid(1000000 + i, cb, handler);
- } else {
- mCm.registerNetworkCallback(networkRequest, cb);
- }
- systemRegistered.add(cb);
- }
- waitForIdle();
-
- assertThrows(TooManyRequestsException.class, () ->
- mCm.registerDefaultNetworkCallbackForUid(1001042, new NetworkCallback(),
- handler));
- assertThrows(TooManyRequestsException.class, () ->
- mCm.registerNetworkCallback(networkRequest, new NetworkCallback()));
-
- for (NetworkCallback callback : systemRegistered) {
- mCm.unregisterNetworkCallback(callback);
- }
- waitForIdle(); // Wait for requests to be unregistered before giving up the permission.
- });
-
- for (Object o : registered) {
- if (o instanceof NetworkCallback) {
- mCm.unregisterNetworkCallback((NetworkCallback)o);
- }
- if (o instanceof PendingIntent) {
- mCm.unregisterNetworkCallback((PendingIntent)o);
- }
- }
- waitForIdle();
-
- // Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.requestNetwork(networkRequest, networkCallback);
- mCm.unregisterNetworkCallback(networkCallback);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
- mCm.unregisterNetworkCallback(networkCallback);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerDefaultNetworkCallback(networkCallback);
- mCm.unregisterNetworkCallback(networkCallback);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerDefaultNetworkCallback(networkCallback);
- mCm.unregisterNetworkCallback(networkCallback);
- }
- waitForIdle();
-
- withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerDefaultNetworkCallbackForUid(1000000 + i, networkCallback,
- new Handler(ConnectivityThread.getInstanceLooper()));
- mCm.unregisterNetworkCallback(networkCallback);
- }
- });
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("e" + i), FLAG_IMMUTABLE);
- mCm.requestNetwork(networkRequest, pendingIntent);
- mCm.unregisterNetworkCallback(pendingIntent);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("f" + i), FLAG_IMMUTABLE);
- mCm.registerNetworkCallback(networkRequest, pendingIntent);
- mCm.unregisterNetworkCallback(pendingIntent);
- }
- }
-
- @Test
- public void testNetworkInfoOfTypeNone() throws Exception {
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
-
- verifyNoNetwork();
- TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE);
- assertNull(mCm.getActiveNetworkInfo());
-
- Network[] allNetworks = mCm.getAllNetworks();
- assertLength(1, allNetworks);
- Network network = allNetworks[0];
- NetworkCapabilities capabilities = mCm.getNetworkCapabilities(network);
- assertTrue(capabilities.hasTransport(TRANSPORT_WIFI_AWARE));
-
- final NetworkRequest request =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI_AWARE).build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up wifi aware network.
- wifiAware.connect(false, false, false /* isStrictMode */);
- callback.expectAvailableCallbacksUnvalidated(wifiAware);
-
- assertNull(mCm.getActiveNetworkInfo());
- assertNull(mCm.getActiveNetwork());
- // TODO: getAllNetworkInfo is dirty and returns a non-empty array right from the start
- // of this test. Fix it and uncomment the assert below.
- //assertEmpty(mCm.getAllNetworkInfo());
-
- // Disconnect wifi aware network.
- wifiAware.disconnect();
- callback.expectCallbackThat(TIMEOUT_MS, (info) -> info instanceof CallbackEntry.Lost);
- mCm.unregisterNetworkCallback(callback);
-
- verifyNoNetwork();
- b.expectNoBroadcast(10);
- }
-
- @Test
- public void testDeprecatedAndUnsupportedOperations() throws Exception {
- final int TYPE_NONE = ConnectivityManager.TYPE_NONE;
- assertNull(mCm.getNetworkInfo(TYPE_NONE));
- assertNull(mCm.getNetworkForType(TYPE_NONE));
- assertNull(mCm.getLinkProperties(TYPE_NONE));
- assertFalse(mCm.isNetworkSupported(TYPE_NONE));
-
- assertThrows(IllegalArgumentException.class,
- () -> mCm.networkCapabilitiesForType(TYPE_NONE));
-
- Class<UnsupportedOperationException> unsupported = UnsupportedOperationException.class;
- assertThrows(unsupported, () -> mCm.startUsingNetworkFeature(TYPE_WIFI, ""));
- assertThrows(unsupported, () -> mCm.stopUsingNetworkFeature(TYPE_WIFI, ""));
- // TODO: let test context have configuration application target sdk version
- // and test that pre-M requesting for TYPE_NONE sends back APN_REQUEST_FAILED
- assertThrows(unsupported, () -> mCm.startUsingNetworkFeature(TYPE_NONE, ""));
- assertThrows(unsupported, () -> mCm.stopUsingNetworkFeature(TYPE_NONE, ""));
- assertThrows(unsupported, () -> mCm.requestRouteToHostAddress(TYPE_NONE, null));
- }
-
- @Test
- public void testLinkPropertiesEnsuresDirectlyConnectedRoutes() throws Exception {
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(WIFI_IFNAME);
- LinkAddress myIpv4Address = new LinkAddress("192.168.12.3/24");
- RouteInfo myIpv4DefaultRoute = new RouteInfo((IpPrefix) null,
- InetAddresses.parseNumericAddress("192.168.12.1"), lp.getInterfaceName());
- lp.addLinkAddress(myIpv4Address);
- lp.addRoute(myIpv4DefaultRoute);
-
- // Verify direct routes are added when network agent is first registered in
- // ConnectivityService.
- TestNetworkAgentWrapper networkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
- networkAgent.connect(true);
- networkCallback.expectCallback(CallbackEntry.AVAILABLE, networkAgent);
- networkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, networkAgent);
- CallbackEntry.LinkPropertiesChanged cbi =
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- networkAgent);
- networkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, networkAgent);
- networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
- networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.getLp(), Arrays.asList(myIpv4Address),
- Arrays.asList(myIpv4DefaultRoute));
- checkDirectlyConnectedRoutes(mCm.getLinkProperties(networkAgent.getNetwork()),
- Arrays.asList(myIpv4Address), Arrays.asList(myIpv4DefaultRoute));
-
- // Verify direct routes are added during subsequent link properties updates.
- LinkProperties newLp = new LinkProperties(lp);
- LinkAddress myIpv6Address1 = new LinkAddress("fe80::cafe/64");
- LinkAddress myIpv6Address2 = new LinkAddress("2001:db8::2/64");
- newLp.addLinkAddress(myIpv6Address1);
- newLp.addLinkAddress(myIpv6Address2);
- networkAgent.sendLinkProperties(newLp);
- cbi = networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, networkAgent);
- networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.getLp(),
- Arrays.asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
- Arrays.asList(myIpv4DefaultRoute));
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- private <T> void assertSameElementsNoDuplicates(T[] expected, T[] actual) {
- // Easier to implement than a proper "assertSameElements" method that also correctly deals
- // with duplicates.
- final String msg = Arrays.toString(expected) + " != " + Arrays.toString(actual);
- assertEquals(msg, expected.length, actual.length);
- Set expectedSet = new ArraySet<>(Arrays.asList(expected));
- assertEquals("expected contains duplicates", expectedSet.size(), expected.length);
- // actual cannot have duplicates because it's the same length and has the same elements.
- Set actualSet = new ArraySet<>(Arrays.asList(actual));
- assertEquals(expectedSet, actualSet);
- }
-
- private void expectNetworkStatus(Network[] networks, String defaultIface,
- Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
- ArgumentCaptor<List<Network>> networksCaptor = ArgumentCaptor.forClass(List.class);
- ArgumentCaptor<List<UnderlyingNetworkInfo>> vpnInfosCaptor =
- ArgumentCaptor.forClass(List.class);
-
- verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(),
- any(List.class), eq(defaultIface), vpnInfosCaptor.capture());
-
- assertSameElementsNoDuplicates(networksCaptor.getValue().toArray(), networks);
-
- UnderlyingNetworkInfo[] infos =
- vpnInfosCaptor.getValue().toArray(new UnderlyingNetworkInfo[0]);
- if (vpnUid != null) {
- assertEquals("Should have exactly one VPN:", 1, infos.length);
- UnderlyingNetworkInfo info = infos[0];
- assertEquals("Unexpected VPN owner:", (int) vpnUid, info.getOwnerUid());
- assertEquals("Unexpected VPN interface:", vpnIfname, info.getInterface());
- assertSameElementsNoDuplicates(underlyingIfaces,
- info.getUnderlyingInterfaces().toArray(new String[0]));
- } else {
- assertEquals(0, infos.length);
- return;
- }
- }
-
- private void expectNetworkStatus(
- Network[] networks, String defaultIface) throws Exception {
- expectNetworkStatus(networks, defaultIface, null, null, new String[0]);
- }
-
- @Test
- public void testStatsIfacesChanged() throws Exception {
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- final Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()};
- final Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()};
-
- LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName(WIFI_IFNAME);
-
- // Simple connection should have updated ifaces
- mCellNetworkAgent.connect(false);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- waitForIdle();
- expectNetworkStatus(onlyCell, MOBILE_IFNAME);
- reset(mStatsManager);
-
- // Default network switch should update ifaces.
- mWiFiNetworkAgent.connect(false);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- waitForIdle();
- assertEquals(wifiLp, mService.getActiveLinkProperties());
- expectNetworkStatus(onlyWifi, WIFI_IFNAME);
- reset(mStatsManager);
-
- // Disconnect should update ifaces.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
- expectNetworkStatus(onlyCell, MOBILE_IFNAME);
- reset(mStatsManager);
-
- // Metered change should update ifaces
- mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- waitForIdle();
- expectNetworkStatus(onlyCell, MOBILE_IFNAME);
- reset(mStatsManager);
-
- mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- waitForIdle();
- expectNetworkStatus(onlyCell, MOBILE_IFNAME);
- reset(mStatsManager);
-
- // Temp metered change shouldn't update ifaces
- mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
- waitForIdle();
- verify(mStatsManager, never()).notifyNetworkStatus(eq(Arrays.asList(onlyCell)),
- any(List.class), eq(MOBILE_IFNAME), any(List.class));
- reset(mStatsManager);
-
- // Roaming change should update ifaces
- mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
- waitForIdle();
- expectNetworkStatus(onlyCell, MOBILE_IFNAME);
- reset(mStatsManager);
-
- // Test VPNs.
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(VPN_IFNAME);
-
- mMockVpn.establishForMyUid(lp);
- assertUidRangesUpdatedForMyUid(true);
-
- final Network[] cellAndVpn = new Network[] {
- mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
-
- // A VPN with default (null) underlying networks sets the underlying network's interfaces...
- expectNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME});
-
- // ...and updates them as the default network switches.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- final Network[] onlyNull = new Network[]{null};
- final Network[] wifiAndVpn = new Network[] {
- mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
- final Network[] cellAndWifi = new Network[] {
- mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()};
- final Network[] cellNullAndWifi = new Network[] {
- mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
-
- waitForIdle();
- assertEquals(wifiLp, mService.getActiveLinkProperties());
- expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{WIFI_IFNAME});
- reset(mStatsManager);
-
- // A VPN that sets its underlying networks passes the underlying interfaces, and influences
- // the default interface sent to NetworkStatsService by virtue of applying to the system
- // server UID (or, in this test, to the test's UID). This is the reason for sending
- // MOBILE_IFNAME even though the default network is wifi.
- // TODO: fix this to pass in the actual default network interface. Whether or not the VPN
- // applies to the system server UID should not have any bearing on network stats.
- mMockVpn.setUnderlyingNetworks(onlyCell);
- waitForIdle();
- expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME});
- reset(mStatsManager);
-
- mMockVpn.setUnderlyingNetworks(cellAndWifi);
- waitForIdle();
- expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME, WIFI_IFNAME});
- reset(mStatsManager);
-
- // Null underlying networks are ignored.
- mMockVpn.setUnderlyingNetworks(cellNullAndWifi);
- waitForIdle();
- expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME, WIFI_IFNAME});
- reset(mStatsManager);
-
- // If an underlying network disconnects, that interface should no longer be underlying.
- // This doesn't actually work because disconnectAndDestroyNetwork only notifies
- // NetworkStatsService before the underlying network is actually removed. So the underlying
- // network will only be removed if notifyIfacesChangedForNetworkStats is called again. This
- // could result in incorrect data usage measurements if the interface used by the
- // disconnected network is reused by a system component that does not register an agent for
- // it (e.g., tethering).
- mCellNetworkAgent.disconnect();
- waitForIdle();
- assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork()));
- expectNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{MOBILE_IFNAME, WIFI_IFNAME});
-
- // Confirm that we never tell NetworkStatsService that cell is no longer the underlying
- // network for the VPN...
- verify(mStatsManager, never()).notifyNetworkStatus(any(List.class),
- any(List.class), any() /* anyString() doesn't match null */,
- argThat(infos -> infos.get(0).getUnderlyingInterfaces().size() == 1
- && WIFI_IFNAME.equals(infos.get(0).getUnderlyingInterfaces().get(0))));
- verifyNoMoreInteractions(mStatsManager);
- reset(mStatsManager);
-
- // ... but if something else happens that causes notifyIfacesChangedForNetworkStats to be
- // called again, it does. For example, connect Ethernet, but with a low score, such that it
- // does not become the default network.
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.setScore(
- new NetworkScore.Builder().setLegacyInt(30).setExiting(true).build());
- mEthernetNetworkAgent.connect(false);
- waitForIdle();
- verify(mStatsManager).notifyNetworkStatus(any(List.class),
- any(List.class), any() /* anyString() doesn't match null */,
- argThat(vpnInfos -> vpnInfos.get(0).getUnderlyingInterfaces().size() == 1
- && WIFI_IFNAME.equals(vpnInfos.get(0).getUnderlyingInterfaces().get(0))));
- mEthernetNetworkAgent.disconnect();
- waitForIdle();
- reset(mStatsManager);
-
- // When a VPN declares no underlying networks (i.e., no connectivity), getAllVpnInfo
- // does not return the VPN, so CS does not pass it to NetworkStatsService. This causes
- // NetworkStatsFactory#adjustForTunAnd464Xlat not to attempt any VPN data migration, which
- // is probably a performance improvement (though it's very unlikely that a VPN would declare
- // no underlying networks).
- // Also, for the same reason as above, the active interface passed in is null.
- mMockVpn.setUnderlyingNetworks(new Network[0]);
- waitForIdle();
- expectNetworkStatus(wifiAndVpn, null);
- reset(mStatsManager);
-
- // Specifying only a null underlying network is the same as no networks.
- mMockVpn.setUnderlyingNetworks(onlyNull);
- waitForIdle();
- expectNetworkStatus(wifiAndVpn, null);
- reset(mStatsManager);
-
- // Specifying networks that are all disconnected is the same as specifying no networks.
- mMockVpn.setUnderlyingNetworks(onlyCell);
- waitForIdle();
- expectNetworkStatus(wifiAndVpn, null);
- reset(mStatsManager);
-
- // Passing in null again means follow the default network again.
- mMockVpn.setUnderlyingNetworks(null);
- waitForIdle();
- expectNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
- new String[]{WIFI_IFNAME});
- reset(mStatsManager);
- }
-
- @Test
- public void testBasicDnsConfigurationPushed() throws Exception {
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-
- // Clear any interactions that occur as a result of CS starting up.
- reset(mMockDnsResolver);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- waitForIdle();
- verify(mMockDnsResolver, never()).setResolverConfiguration(any());
- verifyNoMoreInteractions(mMockDnsResolver);
-
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- // Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
- // "is-reachable" testing in order to not program netd with unreachable
- // nameservers that it might try repeated to validate.
- cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
- MOBILE_IFNAME));
- cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
- MOBILE_IFNAME));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- mCellNetworkAgent.connect(false);
- waitForIdle();
-
- verify(mMockDnsResolver, times(1)).createNetworkCache(
- eq(mCellNetworkAgent.getNetwork().netId));
- // CS tells dnsresolver about the empty DNS config for this network.
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
- reset(mMockDnsResolver);
-
- cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- waitForIdle();
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(1, resolvrParams.servers.length);
- assertTrue(ArrayUtils.contains(resolvrParams.servers, "2001:db8::1"));
- // Opportunistic mode.
- assertTrue(ArrayUtils.contains(resolvrParams.tlsServers, "2001:db8::1"));
- reset(mMockDnsResolver);
-
- cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- waitForIdle();
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
- // Opportunistic mode.
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mMockDnsResolver);
-
- final String TLS_SPECIFIER = "tls.example.com";
- final String TLS_SERVER6 = "2001:db8:53::53";
- final InetAddress[] TLS_IPS = new InetAddress[]{ InetAddress.getByName(TLS_SERVER6) };
- final String[] TLS_SERVERS = new String[]{ TLS_SERVER6 };
- mCellNetworkAgent.mNmCallbacks.notifyPrivateDnsConfigResolved(
- new PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS).toParcel());
-
- waitForIdle();
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mMockDnsResolver);
- }
-
- @Test
- public void testDnsConfigurationTransTypesPushed() throws Exception {
- // Clear any interactions that occur as a result of CS starting up.
- reset(mMockDnsResolver);
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mMockDnsResolver, times(1)).createNetworkCache(
- eq(mWiFiNetworkAgent.getNetwork().netId));
- verify(mMockDnsResolver, times(2)).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- final ResolverParamsParcel resolverParams = mResolverParamsParcelCaptor.getValue();
- assertContainsExactly(resolverParams.transportTypes, TRANSPORT_WIFI);
- reset(mMockDnsResolver);
- }
-
- @Test
- public void testPrivateDnsNotification() throws Exception {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
- // Bring up wifi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // Private DNS resolution failed, checking if the notification will be shown or not.
- mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- // If network validation failed, NetworkMonitor will re-evaluate the network.
- // ConnectivityService should filter the redundant notification. This part is trying to
- // simulate that situation and check if ConnectivityService could filter that case.
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).notify(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any());
- // If private DNS resolution successful, the PRIVATE_DNS_BROKEN notification shouldn't be
- // shown.
- mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).cancel(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId));
- // If private DNS resolution failed again, the PRIVATE_DNS_BROKEN notification should be
- // shown again.
- mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(2)).notify(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any());
- }
-
- @Test
- public void testPrivateDnsSettingsChange() throws Exception {
- // Clear any interactions that occur as a result of CS starting up.
- reset(mMockDnsResolver);
-
- // The default on Android is opportunistic mode ("Automatic").
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- waitForIdle();
- // CS tells netd about the empty DNS config for this network.
- verify(mMockDnsResolver, never()).setResolverConfiguration(any());
- verifyNoMoreInteractions(mMockDnsResolver);
-
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- // Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
- // "is-reachable" testing in order to not program netd with unreachable
- // nameservers that it might try repeated to validate.
- cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
- MOBILE_IFNAME));
- cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
- MOBILE_IFNAME));
- cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
- cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
-
- mCellNetworkAgent.sendLinkProperties(cellLp);
- mCellNetworkAgent.connect(false);
- waitForIdle();
- verify(mMockDnsResolver, times(1)).createNetworkCache(
- eq(mCellNetworkAgent.getNetwork().netId));
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- // Opportunistic mode.
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- reset(mMockDnsResolver);
- cellNetworkCallback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED,
- mCellNetworkAgent);
- CallbackEntry.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
- CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
-
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
- verify(mMockDnsResolver, times(1)).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- reset(mMockDnsResolver);
- cellNetworkCallback.assertNoCallback();
-
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- reset(mMockDnsResolver);
- cellNetworkCallback.assertNoCallback();
-
- setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
- // Can't test dns configuration for strict mode without properly mocking
- // out the DNS lookups, but can test that LinkProperties is updated.
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertTrue(cbi.getLp().isPrivateDnsActive());
- assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName());
- }
-
- private PrivateDnsValidationEventParcel makePrivateDnsValidationEvent(
- final int netId, final String ipAddress, final String hostname, final int validation) {
- final PrivateDnsValidationEventParcel event = new PrivateDnsValidationEventParcel();
- event.netId = netId;
- event.ipAddress = ipAddress;
- event.hostname = hostname;
- event.validation = validation;
- return event;
- }
-
- @Test
- public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception {
- // The default on Android is opportunistic mode ("Automatic").
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- waitForIdle();
- LinkProperties lp = new LinkProperties();
- mCellNetworkAgent.sendLinkProperties(lp);
- mCellNetworkAgent.connect(false);
- waitForIdle();
- cellNetworkCallback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED,
- mCellNetworkAgent);
- CallbackEntry.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
- CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- Set<InetAddress> dnsServers = new HashSet<>();
- checkDnsServers(cbi.getLp(), dnsServers);
-
- // Send a validation event for a server that is not part of the current
- // resolver config. The validation event should be ignored.
- mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
- makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, "",
- "145.100.185.18", VALIDATION_RESULT_SUCCESS));
- cellNetworkCallback.assertNoCallback();
-
- // Add a dns server to the LinkProperties.
- LinkProperties lp2 = new LinkProperties(lp);
- lp2.addDnsServer(InetAddress.getByName("145.100.185.16"));
- mCellNetworkAgent.sendLinkProperties(lp2);
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- dnsServers.add(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.getLp(), dnsServers);
-
- // Send a validation event containing a hostname that is not part of
- // the current resolver config. The validation event should be ignored.
- mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
- makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
- "145.100.185.16", "hostname", VALIDATION_RESULT_SUCCESS));
- cellNetworkCallback.assertNoCallback();
-
- // Send a validation event where validation failed.
- mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
- makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
- "145.100.185.16", "", VALIDATION_RESULT_FAILURE));
- cellNetworkCallback.assertNoCallback();
-
- // Send a validation event where validation succeeded for a server in
- // the current resolver config. A LinkProperties callback with updated
- // private dns fields should be sent.
- mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
- makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
- "145.100.185.16", "", VALIDATION_RESULT_SUCCESS));
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertTrue(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- checkDnsServers(cbi.getLp(), dnsServers);
-
- // The private dns fields in LinkProperties should be preserved when
- // the network agent sends unrelated changes.
- LinkProperties lp3 = new LinkProperties(lp2);
- lp3.setMtu(1300);
- mCellNetworkAgent.sendLinkProperties(lp3);
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertTrue(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- checkDnsServers(cbi.getLp(), dnsServers);
- assertEquals(1300, cbi.getLp().getMtu());
-
- // Removing the only validated server should affect the private dns
- // fields in LinkProperties.
- LinkProperties lp4 = new LinkProperties(lp3);
- lp4.removeDnsServer(InetAddress.getByName("145.100.185.16"));
- mCellNetworkAgent.sendLinkProperties(lp4);
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- dnsServers.remove(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.getLp(), dnsServers);
- assertEquals(1300, cbi.getLp().getMtu());
- }
-
- private void checkDirectlyConnectedRoutes(Object callbackObj,
- Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) {
- assertTrue(callbackObj instanceof LinkProperties);
- LinkProperties lp = (LinkProperties) callbackObj;
-
- Set<RouteInfo> expectedRoutes = new ArraySet<>();
- expectedRoutes.addAll(otherRoutes);
- for (LinkAddress address : linkAddresses) {
- RouteInfo localRoute = new RouteInfo(address, null, lp.getInterfaceName());
- // Duplicates in linkAddresses are considered failures
- assertTrue(expectedRoutes.add(localRoute));
- }
- List<RouteInfo> observedRoutes = lp.getRoutes();
- assertEquals(expectedRoutes.size(), observedRoutes.size());
- assertTrue(observedRoutes.containsAll(expectedRoutes));
- }
-
- private static void checkDnsServers(Object callbackObj, Set<InetAddress> dnsServers) {
- assertTrue(callbackObj instanceof LinkProperties);
- LinkProperties lp = (LinkProperties) callbackObj;
- assertEquals(dnsServers.size(), lp.getDnsServers().size());
- assertTrue(lp.getDnsServers().containsAll(dnsServers));
- }
-
- @Test
- public void testApplyUnderlyingCapabilities() throws Exception {
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mCellNetworkAgent.connect(false /* validated */);
- mWiFiNetworkAgent.connect(false /* validated */);
-
- final NetworkCapabilities cellNc = new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .setLinkDownstreamBandwidthKbps(10);
- final NetworkCapabilities wifiNc = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .setLinkUpstreamBandwidthKbps(20);
- mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
- mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
- waitForIdle();
-
- final Network mobile = mCellNetworkAgent.getNetwork();
- final Network wifi = mWiFiNetworkAgent.getNetwork();
-
- final NetworkCapabilities initialCaps = new NetworkCapabilities();
- initialCaps.addTransportType(TRANSPORT_VPN);
- initialCaps.addCapability(NET_CAPABILITY_INTERNET);
- initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN);
-
- final NetworkCapabilities withNoUnderlying = new NetworkCapabilities();
- withNoUnderlying.addCapability(NET_CAPABILITY_INTERNET);
- withNoUnderlying.addCapability(NET_CAPABILITY_NOT_CONGESTED);
- withNoUnderlying.addCapability(NET_CAPABILITY_NOT_ROAMING);
- withNoUnderlying.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- withNoUnderlying.addTransportType(TRANSPORT_VPN);
- withNoUnderlying.removeCapability(NET_CAPABILITY_NOT_VPN);
-
- final NetworkCapabilities withMobileUnderlying = new NetworkCapabilities(withNoUnderlying);
- withMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
- withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
- withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- withMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
-
- final NetworkCapabilities withWifiUnderlying = new NetworkCapabilities(withNoUnderlying);
- withWifiUnderlying.addTransportType(TRANSPORT_WIFI);
- withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
- withWifiUnderlying.setLinkUpstreamBandwidthKbps(20);
-
- final NetworkCapabilities withWifiAndMobileUnderlying =
- new NetworkCapabilities(withNoUnderlying);
- withWifiAndMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
- withWifiAndMobileUnderlying.addTransportType(TRANSPORT_WIFI);
- withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
- withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
- withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
- withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20);
-
- final NetworkCapabilities initialCapsNotMetered = new NetworkCapabilities(initialCaps);
- initialCapsNotMetered.addCapability(NET_CAPABILITY_NOT_METERED);
-
- NetworkCapabilities caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{}, initialCapsNotMetered, caps);
- assertEquals(withNoUnderlying, caps);
-
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{null}, initialCapsNotMetered, caps);
- assertEquals(withNoUnderlying, caps);
-
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{mobile}, initialCapsNotMetered, caps);
- assertEquals(withMobileUnderlying, caps);
-
- mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCapsNotMetered, caps);
- assertEquals(withWifiUnderlying, caps);
-
- withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCaps, caps);
- assertEquals(withWifiUnderlying, caps);
-
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, initialCaps, caps);
- assertEquals(withWifiAndMobileUnderlying, caps);
-
- withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
- initialCapsNotMetered, caps);
- assertEquals(withWifiAndMobileUnderlying, caps);
-
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
- initialCapsNotMetered, caps);
- assertEquals(withWifiAndMobileUnderlying, caps);
-
- mService.applyUnderlyingCapabilities(null, initialCapsNotMetered, caps);
- assertEquals(withWifiUnderlying, caps);
- }
-
- @Test
- public void testVpnConnectDisconnectUnderlyingNetwork() throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN).build();
-
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up a VPN that specifies an underlying network that does not exist yet.
- // Note: it's sort of meaningless for a VPN app to declare a network that doesn't exist yet,
- // (and doing so is difficult without using reflection) but it's good to test that the code
- // behaves approximately correctly.
- mMockVpn.establishForMyUid(false, true, false);
- assertUidRangesUpdatedForMyUid(true);
- final Network wifiNetwork = new Network(mNetIdManager.peekNextNetId());
- mMockVpn.setUnderlyingNetworks(new Network[]{wifiNetwork});
- callback.expectAvailableCallbacksUnvalidated(mMockVpn);
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_VPN));
- assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_WIFI));
-
- // Make that underlying network connect, and expect to see its capabilities immediately
- // reflected in the VPN's capabilities.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- assertEquals(wifiNetwork, mWiFiNetworkAgent.getNetwork());
- mWiFiNetworkAgent.connect(false);
- // TODO: the callback for the VPN happens before any callbacks are called for the wifi
- // network that has just connected. There appear to be two issues here:
- // 1. The VPN code will accept an underlying network as soon as getNetworkCapabilities() for
- // it returns non-null (which happens very early, during handleRegisterNetworkAgent).
- // This is not correct because that that point the network is not connected and cannot
- // pass any traffic.
- // 2. When a network connects, updateNetworkInfo propagates underlying network capabilities
- // before rematching networks.
- // Given that this scenario can't really happen, this is probably fine for now.
- callback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_VPN));
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_WIFI));
-
- // Disconnect the network, and expect to see the VPN capabilities change accordingly.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- callback.expectCapabilitiesThat(mMockVpn, (nc) ->
- nc.getTransportTypes().length == 1 && nc.hasTransport(TRANSPORT_VPN));
-
- mMockVpn.disconnect();
- mCm.unregisterNetworkCallback(callback);
- }
-
- private void assertGetNetworkInfoOfGetActiveNetworkIsConnected(boolean expectedConnectivity) {
- // What Chromium used to do before https://chromium-review.googlesource.com/2605304
- assertEquals("Unexpected result for getActiveNetworkInfo(getActiveNetwork())",
- expectedConnectivity, mCm.getNetworkInfo(mCm.getActiveNetwork()).isConnected());
- }
-
- @Test
- public void testVpnUnderlyingNetworkSuspended() throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
-
- // Connect a VPN.
- mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */,
- false /* isStrictMode */);
- callback.expectAvailableCallbacksUnvalidated(mMockVpn);
-
- // Connect cellular data.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false /* validated */);
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
-
- // Suspend the cellular network and expect the VPN to be suspended.
- mCellNetworkAgent.suspend();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
- callback.assertNoCallback();
-
- assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- // VPN's main underlying network is suspended, so no connectivity.
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
-
- // Switch to another network. The VPN should no longer be suspended.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false /* validated */);
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_WIFI));
- callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
-
- // Unsuspend cellular and then switch back to it. The VPN remains not suspended.
- mCellNetworkAgent.resume();
- callback.assertNoCallback();
- mWiFiNetworkAgent.disconnect();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- // Spurious double callback?
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
-
- // Suspend cellular and expect no connectivity.
- mCellNetworkAgent.suspend();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
- callback.assertNoCallback();
-
- assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
-
- // Resume cellular and expect that connectivity comes back.
- mCellNetworkAgent.resume();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
- }
-
- @Test
- public void testVpnNetworkActive() throws Exception {
- // NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final int uid = Process.myUid();
-
- final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback genericNotVpnNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
- final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
- final NetworkRequest genericRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN).build();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN).build();
- mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
- mCm.registerNetworkCallback(genericNotVpnRequest, genericNotVpnNetworkCallback);
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- mCm.registerDefaultNetworkCallback(defaultCallback);
- mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback,
- new Handler(ConnectivityThread.getInstanceLooper()));
- defaultCallback.assertNoCallback();
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
-
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- vpnNetworkCallback.assertNoCallback();
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- final Set<UidRange> ranges = uidRangesForUids(uid);
- mMockVpn.registerAgent(ranges);
- mMockVpn.setUnderlyingNetworks(new Network[0]);
-
- // VPN networks do not satisfy the default request and are automatically validated
- // by NetworkMonitor
- assertFalse(NetworkMonitorUtils.isValidationRequired(
- mMockVpn.getAgent().getNetworkCapabilities()));
- mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
-
- mMockVpn.connect(false);
-
- genericNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- systemDefaultCallback.assertNoCallback();
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(mWiFiNetworkAgent.getNetwork(),
- systemDefaultCallback.getLastAvailableNetwork());
-
- ranges.clear();
- mMockVpn.setUids(ranges);
-
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
-
- // TODO : The default network callback should actually get a LOST call here (also see the
- // comment below for AVAILABLE). This is because ConnectivityService does not look at UID
- // ranges at all when determining whether a network should be rematched. In practice, VPNs
- // can't currently update their UIDs without disconnecting, so this does not matter too
- // much, but that is the reason the test here has to check for an update to the
- // capabilities instead of the expected LOST then AVAILABLE.
- defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
- systemDefaultCallback.assertNoCallback();
-
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setUids(ranges);
-
- genericNetworkCallback.expectAvailableCallbacksValidated(mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectAvailableCallbacksValidated(mMockVpn);
- // TODO : Here like above, AVAILABLE would be correct, but because this can't actually
- // happen outside of the test, ConnectivityService does not rematch callbacks.
- defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
- systemDefaultCallback.assertNoCallback();
-
- mWiFiNetworkAgent.disconnect();
-
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- genericNotVpnNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- vpnNetworkCallback.assertNoCallback();
- defaultCallback.assertNoCallback();
- systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- mMockVpn.disconnect();
-
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- systemDefaultCallback.assertNoCallback();
- assertEquals(null, mCm.getActiveNetwork());
-
- mCm.unregisterNetworkCallback(genericNetworkCallback);
- mCm.unregisterNetworkCallback(wifiNetworkCallback);
- mCm.unregisterNetworkCallback(vpnNetworkCallback);
- mCm.unregisterNetworkCallback(defaultCallback);
- mCm.unregisterNetworkCallback(systemDefaultCallback);
- }
-
- @Test
- public void testVpnWithoutInternet() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
-
- defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- defaultCallback.assertNoCallback();
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.disconnect();
- defaultCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- @Test
- public void testVpnWithInternet() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
-
- defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.establishForMyUid(true /* validated */, true /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
-
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- @Test
- public void testVpnUnvalidated() throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
-
- // Bring up Ethernet.
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
- callback.assertNoCallback();
-
- // Bring up a VPN that has the INTERNET capability, initially unvalidated.
- mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- // Even though the VPN is unvalidated, it becomes the default network for our app.
- callback.expectAvailableCallbacksUnvalidated(mMockVpn);
- callback.assertNoCallback();
-
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED));
- assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
-
- assertFalse(NetworkMonitorUtils.isValidationRequired(
- mMockVpn.getAgent().getNetworkCapabilities()));
- assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired(
- mMockVpn.getAgent().getNetworkCapabilities()));
-
- // Pretend that the VPN network validates.
- mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
- mMockVpn.getAgent().mNetworkMonitor.forceReevaluation(Process.myUid());
- // Expect to see the validated capability, but no other changes, because the VPN is already
- // the default network for the app.
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mMockVpn);
- callback.assertNoCallback();
-
- mMockVpn.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mMockVpn);
- callback.expectAvailableCallbacksValidated(mEthernetNetworkAgent);
- }
-
- @Test
- public void testVpnStartsWithUnderlyingCaps() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN)
- .build();
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- vpnNetworkCallback.assertNoCallback();
-
- // Connect cell. It will become the default network, and in the absence of setting
- // underlying networks explicitly it will become the sole underlying network for the vpn.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mCellNetworkAgent.connect(true);
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- vpnNetworkCallback.expectAvailableCallbacks(mMockVpn.getNetwork(),
- false /* suspended */, false /* validated */, false /* blocked */, TIMEOUT_MS);
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn.getNetwork(), TIMEOUT_MS,
- nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED));
-
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- assertTrue(nc.hasCapability(NET_CAPABILITY_VALIDATED));
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
- }
-
- private void assertDefaultNetworkCapabilities(int userId, NetworkAgentWrapper... networks) {
- final NetworkCapabilities[] defaultCaps = mService.getDefaultNetworkCapabilitiesForUser(
- userId, "com.android.calling.package", "com.test");
- final String defaultCapsString = Arrays.toString(defaultCaps);
- assertEquals(defaultCapsString, defaultCaps.length, networks.length);
- final Set<NetworkCapabilities> defaultCapsSet = new ArraySet<>(defaultCaps);
- for (NetworkAgentWrapper network : networks) {
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
- final String msg = "Did not find " + nc + " in " + Arrays.toString(defaultCaps);
- assertTrue(msg, defaultCapsSet.contains(nc));
- }
- }
-
- @Test
- public void testVpnSetUnderlyingNetworks() throws Exception {
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN)
- .build();
- NetworkCapabilities nc;
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- vpnNetworkCallback.assertNoCallback();
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- // For safety reasons a VPN without underlying networks is considered metered.
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
- // A VPN without underlying networks is not suspended.
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
-
- final int userId = UserHandle.getUserId(Process.myUid());
- assertDefaultNetworkCapabilities(userId /* no networks */);
-
- // Connect cell and use it as an underlying network.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mCellNetworkAgent.connect(true);
-
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mWiFiNetworkAgent.connect(true);
-
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Don't disconnect, but note the VPN is not using wifi any more.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- // The return value of getDefaultNetworkCapabilitiesForUser always includes the default
- // network (wifi) as well as the underlying networks (cell).
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Remove NOT_SUSPENDED from the only network and observe VPN is now suspended.
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
-
- // Add NOT_SUSPENDED again and observe VPN is no longer suspended.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
-
- // Use Wifi but not cell. Note the VPN is now unmetered and not suspended.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent);
-
- // Use both again.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Cell is suspended again. As WiFi is not, this should not cause a callback.
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.assertNoCallback();
-
- // Stop using WiFi. The VPN is suspended again.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Use both again.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Disconnect cell. Receive update without even removing the dead network from the
- // underlying networks – it's dead anyway. Not metered any more.
- mCellNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent);
-
- // Disconnect wifi too. No underlying networks means this is now metered.
- mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- // When a network disconnects, the callbacks are fired before all state is updated, so for a
- // short time, synchronous calls will behave as if the network is still connected. Wait for
- // things to settle.
- waitForIdle();
- assertDefaultNetworkCapabilities(userId /* no networks */);
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testNullUnderlyingNetworks() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN)
- .build();
- NetworkCapabilities nc;
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- vpnNetworkCallback.assertNoCallback();
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- // By default, VPN is set to track default network (i.e. its underlying networks is null).
- // In case of no default network, VPN is considered metered.
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
-
- // Connect to Cell; Cell is the default network.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- // Connect to WiFi; WiFi is the new default.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- // Disconnect Cell. The default network did not change, so there shouldn't be any changes in
- // the capabilities.
- mCellNetworkAgent.disconnect();
-
- // Disconnect wifi too. Now we have no default network.
- mWiFiNetworkAgent.disconnect();
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testRestrictedProfileAffectsVpnUidRanges() throws Exception {
- // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up a VPN
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
- callback.expectAvailableThenValidatedCallbacks(mMockVpn);
- callback.assertNoCallback();
-
- final int uid = Process.myUid();
- NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertNotNull("nc=" + nc, nc.getUids());
- assertEquals(nc.getUids(), UidRange.toIntRanges(uidRangesForUids(uid)));
- assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
-
- // Set an underlying network and expect to see the VPN transports change.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCapabilitiesThat(mMockVpn, (caps)
- -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_WIFI));
- callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps)
- -> caps.hasCapability(NET_CAPABILITY_VALIDATED));
-
- when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
- .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
-
- final Intent addedIntent = new Intent(ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
-
- // Send a USER_ADDED broadcast for it.
- processBroadcast(addedIntent);
-
- // Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
- // restricted user.
- final UidRange rRange = UidRange.createForUser(UserHandle.of(RESTRICTED_USER));
- final Range<Integer> restrictUidRange = new Range<Integer>(rRange.start, rRange.stop);
- final Range<Integer> singleUidRange = new Range<Integer>(uid, uid);
- callback.expectCapabilitiesThat(mMockVpn, (caps)
- -> caps.getUids().size() == 2
- && caps.getUids().contains(singleUidRange)
- && caps.getUids().contains(restrictUidRange)
- && caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_WIFI));
-
- // Change the VPN's capabilities somehow (specifically, disconnect wifi).
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- callback.expectCapabilitiesThat(mMockVpn, (caps)
- -> caps.getUids().size() == 2
- && caps.getUids().contains(singleUidRange)
- && caps.getUids().contains(restrictUidRange)
- && caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_WIFI));
-
- // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
- final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
- removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
- removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- processBroadcast(removedIntent);
-
- // Expect that the VPN gains the UID range for the restricted user, and that the capability
- // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
- callback.expectCapabilitiesThat(mMockVpn, (caps)
- -> caps.getUids().size() == 1
- && caps.getUids().contains(singleUidRange)
- && caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_WIFI));
- }
-
- @Test
- public void testLockdownVpnWithRestrictedProfiles() throws Exception {
- // For ConnectivityService#setAlwaysOnVpnPackage.
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
- // For call Vpn#setAlwaysOnPackage.
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
- // Necessary to see the UID ranges in NetworkCapabilities.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- final int uid = Process.myUid();
-
- // Connect wifi and check that UIDs in the main and restricted profiles have network access.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true /* validated */);
- final int restrictedUid = UserHandle.getUid(RESTRICTED_USER, 42 /* appId */);
- assertNotNull(mCm.getActiveNetworkForUid(uid));
- assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
-
- // Enable always-on VPN lockdown. The main user loses network access because no VPN is up.
- final ArrayList<String> allowList = new ArrayList<>();
- mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE,
- true /* lockdown */, allowList);
- waitForIdle();
- assertNull(mCm.getActiveNetworkForUid(uid));
- // This is arguably overspecified: a UID that is not running doesn't have an active network.
- // But it's useful to check that non-default users do not lose network access, and to prove
- // that the loss of connectivity below is indeed due to the restricted profile coming up.
- assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
-
- // Start the restricted profile, and check that the UID within it loses network access.
- when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
- .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
- when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO,
- RESTRICTED_USER_INFO));
- // TODO: check that VPN app within restricted profile still has access, etc.
- final Intent addedIntent = new Intent(ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- processBroadcast(addedIntent);
- assertNull(mCm.getActiveNetworkForUid(uid));
- assertNull(mCm.getActiveNetworkForUid(restrictedUid));
-
- // Stop the restricted profile, and check that the UID within it has network access again.
- when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
-
- // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
- final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
- removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
- removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- processBroadcast(removedIntent);
- assertNull(mCm.getActiveNetworkForUid(uid));
- assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
-
- mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */,
- allowList);
- waitForIdle();
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverWifi() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
-
- assertFalse(mCm.isActiveNetworkMetered());
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverCell() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- waitForIdle();
-
- assertTrue(mCm.isActiveNetworkMetered());
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverVpnTrackingPlatformDefault() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- assertTrue(mCm.isActiveNetworkMetered());
-
- // Connect VPN network. By default it is using current default network (Cell).
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
-
- // Ensure VPN is now the active network.
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- // Expect VPN to be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // Connect WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- // VPN should still be the active network.
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- // Expect VPN to be unmetered as it should now be using WiFi (new default).
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Disconnecting Cell should not affect VPN's meteredness.
- mCellNetworkAgent.disconnect();
- waitForIdle();
-
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Disconnect WiFi; Now there is no platform default network.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
-
- // VPN without any underlying networks is treated as metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverVpnSpecifyingUnderlyingNetworks() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- assertTrue(mCm.isActiveNetworkMetered());
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Connect VPN network.
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
-
- // Ensure VPN is now the active network.
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
- // VPN is using Cell
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Expect VPN to be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // VPN is now using WiFi
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mWiFiNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Expect VPN to be unmetered
- assertFalse(mCm.isActiveNetworkMetered());
-
- // VPN is using Cell | WiFi.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Expect VPN to be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // VPN is using WiFi | Cell.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mWiFiNetworkAgent.getNetwork(), mCellNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Order should not matter and VPN should still be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // VPN is not using any underlying networks.
- mMockVpn.setUnderlyingNetworks(new Network[0]);
- waitForIdle();
-
- // VPN without underlying networks is treated as metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverAlwaysMeteredVpn() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Connect VPN network.
- mMockVpn.registerAgent(true /* isAlwaysMetered */, uidRangesForUids(Process.myUid()),
- new LinkProperties());
- mMockVpn.connect(true);
- waitForIdle();
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- // VPN is tracking current platform default (WiFi).
- mMockVpn.setUnderlyingNetworks(null);
- waitForIdle();
-
- // Despite VPN using WiFi (which is unmetered), VPN itself is marked as always metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
-
- // VPN explicitly declares WiFi as its underlying network.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mWiFiNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Doesn't really matter whether VPN declares its underlying networks explicitly.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // With WiFi lost, VPN is basically without any underlying networks. And in that case it is
- // anyways suppose to be metered.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
-
- assertTrue(mCm.isActiveNetworkMetered());
-
- mMockVpn.disconnect();
- }
-
- private class DetailedBlockedStatusCallback extends TestNetworkCallback {
- public void expectAvailableThenValidatedCallbacks(HasNetwork n, int blockedStatus) {
- super.expectAvailableThenValidatedCallbacks(n.getNetwork(), blockedStatus, TIMEOUT_MS);
- }
- public void expectBlockedStatusCallback(HasNetwork n, int blockedStatus) {
- // This doesn't work:
- // super.expectBlockedStatusCallback(blockedStatus, n.getNetwork());
- super.expectBlockedStatusCallback(blockedStatus, n.getNetwork(), TIMEOUT_MS);
- }
- public void onBlockedStatusChanged(Network network, int blockedReasons) {
- getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
- }
- }
-
- @Test
- public void testNetworkBlockedStatus() throws Exception {
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .build();
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
- final DetailedBlockedStatusCallback detailedCallback = new DetailedBlockedStatusCallback();
- mCm.registerNetworkCallback(cellRequest, detailedCallback);
-
- mockUidNetworkingBlocked();
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- detailedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent,
- BLOCKED_REASON_NONE);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
- BLOCKED_REASON_BATTERY_SAVER);
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mCellNetworkAgent);
-
- // If blocked state does not change but blocked reason does, the boolean callback is called.
- // TODO: investigate de-duplicating.
- setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
- BLOCKED_METERED_REASON_USER_RESTRICTED);
-
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
- BLOCKED_METERED_REASON_DATA_SAVER);
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mCellNetworkAgent);
-
- // Restrict the network based on UID rule and NOT_METERED capability change.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- detailedCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
- mCellNetworkAgent);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- detailedCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
- mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
- BLOCKED_METERED_REASON_DATA_SAVER);
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mCellNetworkAgent);
-
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- cellNetworkCallback.assertNoCallback();
- detailedCallback.assertNoCallback();
-
- // Restrict background data. Networking is not blocked because the network is unmetered.
- setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
- BLOCKED_METERED_REASON_DATA_SAVER);
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mCellNetworkAgent);
- setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
- cellNetworkCallback.assertNoCallback();
-
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- cellNetworkCallback.assertNoCallback();
- detailedCallback.assertNoCallback();
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- }
-
- @Test
- public void testNetworkBlockedStatusBeforeAndAfterConnect() throws Exception {
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
- mockUidNetworkingBlocked();
-
- // No Networkcallbacks invoked before any network is active.
- setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
- defaultCallback.assertNoCallback();
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent);
-
- // Allow to use the network after switching to NOT_METERED network.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-
- // Switch to METERED network. Restrict the use of the network.
- mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidatedAndBlocked(mCellNetworkAgent);
-
- // Network becomes NOT_METERED.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
- defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
-
- // Verify there's no Networkcallbacks invoked after data saver on/off.
- setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- defaultCallback.assertNoCallback();
-
- mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- private void expectNetworkRejectNonSecureVpn(InOrder inOrder, boolean add,
- UidRangeParcel... expected) throws Exception {
- inOrder.verify(mMockNetd).networkRejectNonSecureVpn(eq(add), aryEq(expected));
- }
-
- private void checkNetworkInfo(NetworkInfo ni, int type, DetailedState state) {
- assertNotNull(ni);
- assertEquals(type, ni.getType());
- assertEquals(ConnectivityManager.getNetworkTypeName(type), state, ni.getDetailedState());
- if (state == DetailedState.CONNECTED || state == DetailedState.SUSPENDED) {
- assertNotNull(ni.getExtraInfo());
- } else {
- // Technically speaking, a network that's in CONNECTING state will generally have a
- // non-null extraInfo. This doesn't actually happen in this test because it never calls
- // a legacy API while a network is connecting. When a network is in CONNECTING state
- // because of legacy lockdown VPN, its extraInfo is always null.
- assertNull(ni.getExtraInfo());
- }
- }
-
- private void assertActiveNetworkInfo(int type, DetailedState state) {
- checkNetworkInfo(mCm.getActiveNetworkInfo(), type, state);
- }
- private void assertNetworkInfo(int type, DetailedState state) {
- checkNetworkInfo(mCm.getNetworkInfo(type), type, state);
- }
-
- private void assertExtraInfoFromCm(TestNetworkAgentWrapper network, boolean present) {
- final NetworkInfo niForNetwork = mCm.getNetworkInfo(network.getNetwork());
- final NetworkInfo niForType = mCm.getNetworkInfo(network.getLegacyType());
- if (present) {
- assertEquals(network.getExtraInfo(), niForNetwork.getExtraInfo());
- assertEquals(network.getExtraInfo(), niForType.getExtraInfo());
- } else {
- assertNull(niForNetwork.getExtraInfo());
- assertNull(niForType.getExtraInfo());
- }
- }
-
- private void assertExtraInfoFromCmBlocked(TestNetworkAgentWrapper network) {
- assertExtraInfoFromCm(network, false);
- }
-
- private void assertExtraInfoFromCmPresent(TestNetworkAgentWrapper network) {
- assertExtraInfoFromCm(network, true);
- }
-
- // Checks that each of the |agents| receive a blocked status change callback with the specified
- // |blocked| value, in any order. This is needed because when an event affects multiple
- // networks, ConnectivityService does not guarantee the order in which callbacks are fired.
- private void assertBlockedCallbackInAnyOrder(TestNetworkCallback callback, boolean blocked,
- TestNetworkAgentWrapper... agents) {
- final List<Network> expectedNetworks = Arrays.asList(agents).stream()
- .map((agent) -> agent.getNetwork())
- .collect(Collectors.toList());
-
- // Expect exactly one blocked callback for each agent.
- for (int i = 0; i < agents.length; i++) {
- CallbackEntry e = callback.expectCallbackThat(TIMEOUT_MS, (c) ->
- c instanceof CallbackEntry.BlockedStatus
- && ((CallbackEntry.BlockedStatus) c).getBlocked() == blocked);
- Network network = e.getNetwork();
- assertTrue("Received unexpected blocked callback for network " + network,
- expectedNetworks.remove(network));
- }
- }
-
- @Test
- public void testNetworkBlockedStatusAlwaysOnVpn() throws Exception {
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TestNetworkCallback callback = new TestNetworkCallback();
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .build();
- mCm.registerNetworkCallback(request, callback);
-
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- final TestNetworkCallback vpnUidCallback = new TestNetworkCallback();
- final NetworkRequest vpnUidRequest = new NetworkRequest.Builder().build();
- registerNetworkCallbackAsUid(vpnUidRequest, vpnUidCallback, VPN_UID);
-
- final TestNetworkCallback vpnUidDefaultCallback = new TestNetworkCallback();
- registerDefaultNetworkCallbackAsUid(vpnUidDefaultCallback, VPN_UID);
-
- final TestNetworkCallback vpnDefaultCallbackAsUid = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallbackForUid(VPN_UID, vpnDefaultCallbackAsUid,
- new Handler(ConnectivityThread.getInstanceLooper()));
-
- final int uid = Process.myUid();
- final int userId = UserHandle.getUserId(uid);
- final ArrayList<String> allowList = new ArrayList<>();
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
- waitForIdle();
-
- UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1);
- UidRangeParcel secondHalf = new UidRangeParcel(VPN_UID + 1, 99999);
- InOrder inOrder = inOrder(mMockNetd);
- expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
-
- // Connect a network when lockdown is active, expect to see it blocked.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false /* validated */);
- callback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
- vpnUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- vpnUidDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- vpnDefaultCallbackAsUid.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- // Mobile is BLOCKED even though it's not actually connected.
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
-
- // Disable lockdown, expect to see the network unblocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
- callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
- defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- // Add our UID to the allowlist and re-enable lockdown, expect network is not blocked.
- allowList.add(TEST_PACKAGE_NAME);
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
- callback.assertNoCallback();
- defaultCallback.assertNoCallback();
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
-
- // The following requires that the UID of this test package is greater than VPN_UID. This
- // is always true in practice because a plain AOSP build with no apps installed has almost
- // 200 packages installed.
- final UidRangeParcel piece1 = new UidRangeParcel(1, VPN_UID - 1);
- final UidRangeParcel piece2 = new UidRangeParcel(VPN_UID + 1, uid - 1);
- final UidRangeParcel piece3 = new UidRangeParcel(uid + 1, 99999);
- expectNetworkRejectNonSecureVpn(inOrder, true, piece1, piece2, piece3);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- // Connect a new network, expect it to be unblocked.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false /* validated */);
- callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- defaultCallback.assertNoCallback();
- vpnUidCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- // Cellular is DISCONNECTED because it's not the default and there are no requests for it.
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- // Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
- // Everything should now be blocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
- waitForIdle();
- expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3);
- allowList.clear();
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
- waitForIdle();
- expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
- defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
- assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
-
- // Disable lockdown. Everything is unblocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
- defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
- assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent);
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- // Enable and disable an always-on VPN package without lockdown. Expect no changes.
- reset(mMockNetd);
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, false /* lockdown */,
- allowList);
- inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
- callback.assertNoCallback();
- defaultCallback.assertNoCallback();
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
- inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
- callback.assertNoCallback();
- defaultCallback.assertNoCallback();
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- // Enable lockdown and connect a VPN. The VPN is not blocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
- defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
- assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
-
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- vpnUidCallback.assertNoCallback(); // vpnUidCallback has NOT_VPN capability.
- vpnUidDefaultCallback.assertNoCallback(); // VPN does not apply to VPN_UID
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- mMockVpn.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertNull(mCm.getActiveNetwork());
-
- mCm.unregisterNetworkCallback(callback);
- mCm.unregisterNetworkCallback(defaultCallback);
- mCm.unregisterNetworkCallback(vpnUidCallback);
- mCm.unregisterNetworkCallback(vpnUidDefaultCallback);
- mCm.unregisterNetworkCallback(vpnDefaultCallbackAsUid);
- }
-
- private void setupLegacyLockdownVpn() {
- final String profileName = "testVpnProfile";
- final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8);
- when(mVpnProfileStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag);
-
- final VpnProfile profile = new VpnProfile(profileName);
- profile.name = "My VPN";
- profile.server = "192.0.2.1";
- profile.dnsServers = "8.8.8.8";
- profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
- final byte[] encodedProfile = profile.encode();
- when(mVpnProfileStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
- }
-
- private void establishLegacyLockdownVpn(Network underlying) throws Exception {
- // The legacy lockdown VPN only supports userId 0, and must have an underlying network.
- assertNotNull(underlying);
- mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY);
- // The legacy lockdown VPN only supports userId 0.
- final Set<UidRange> ranges = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.registerAgent(ranges);
- mMockVpn.setUnderlyingNetworks(new Network[]{underlying});
- mMockVpn.connect(true);
- }
-
- @Test
- public void testLegacyLockdownVpn() throws Exception {
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
- // For LockdownVpnTracker to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
- mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback,
- new Handler(ConnectivityThread.getInstanceLooper()));
-
- // Pretend lockdown VPN was configured.
- setupLegacyLockdownVpn();
-
- // LockdownVpnTracker disables the Vpn teardown code and enables lockdown.
- // Check the VPN's state before it does so.
- assertTrue(mMockVpn.getEnableTeardown());
- assertFalse(mMockVpn.getLockdown());
-
- // Send a USER_UNLOCKED broadcast so CS starts LockdownVpnTracker.
- final int userId = UserHandle.getUserId(Process.myUid());
- final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED);
- addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- processBroadcast(addedIntent);
-
- // Lockdown VPN disables teardown and enables lockdown.
- assertFalse(mMockVpn.getEnableTeardown());
- assertTrue(mMockVpn.getLockdown());
-
- // Bring up a network.
- // Expect nothing to happen because the network does not have an IPv4 default route: legacy
- // VPN only supports IPv4.
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName("rmnet0");
- cellLp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
- cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, "rmnet0"));
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- mCellNetworkAgent.connect(false /* validated */);
- callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- waitForIdle();
- assertNull(mMockVpn.getAgent());
-
- // Add an IPv4 address. Ideally the VPN should start, but it doesn't because nothing calls
- // LockdownVpnTracker#handleStateChangedLocked. This is a bug.
- // TODO: consider fixing this.
- cellLp.addLinkAddress(new LinkAddress("192.0.2.2/25"));
- cellLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "rmnet0"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- callback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- systemDefaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- waitForIdle();
- assertNull(mMockVpn.getAgent());
-
- // Disconnect, then try again with a network that supports IPv4 at connection time.
- // Expect lockdown VPN to come up.
- ExpectedBroadcast b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
- mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- systemDefaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- b1.expectBroadcast();
-
- // When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten
- // with the state of the VPN network. So expect a CONNECTING broadcast.
- b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTING);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- mCellNetworkAgent.connect(false /* validated */);
- callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- b1.expectBroadcast();
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mCellNetworkAgent);
-
- // TODO: it would be nice if we could simply rely on the production code here, and have
- // LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with
- // ConnectivityService, etc. That would require duplicating a fair bit of code from the
- // Vpn tests around how to mock out LegacyVpnRunner. But even if we did that, this does not
- // work for at least two reasons:
- // 1. In this test, calling registerNetworkAgent does not actually result in an agent being
- // registered. This is because nothing calls onNetworkMonitorCreated, which is what
- // actually ends up causing handleRegisterNetworkAgent to be called. Code in this test
- // that wants to register an agent must use TestNetworkAgentWrapper.
- // 2. Even if we exposed Vpn#agentConnect to the test, and made MockVpn#agentConnect call
- // the TestNetworkAgentWrapper code, this would deadlock because the
- // TestNetworkAgentWrapper code cannot be called on the handler thread since it calls
- // waitForIdle().
- mMockVpn.expectStartLegacyVpnRunner();
- b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
- ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- establishLegacyLockdownVpn(mCellNetworkAgent.getNetwork());
- callback.expectAvailableThenValidatedCallbacks(mMockVpn);
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- systemDefaultCallback.assertNoCallback();
- NetworkCapabilities vpnNc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- b1.expectBroadcast();
- b2.expectBroadcast();
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
- assertTrue(vpnNc.hasTransport(TRANSPORT_VPN));
- assertTrue(vpnNc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(vpnNc.hasTransport(TRANSPORT_WIFI));
- assertFalse(vpnNc.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertVpnTransportInfo(vpnNc, VpnManager.TYPE_VPN_LEGACY);
-
- // Switch default network from cell to wifi. Expect VPN to disconnect and reconnect.
- final LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName("wlan0");
- wifiLp.addLinkAddress(new LinkAddress("192.0.2.163/25"));
- wifiLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "wlan0"));
- final NetworkCapabilities wifiNc = new NetworkCapabilities();
- wifiNc.addTransportType(TRANSPORT_WIFI);
- wifiNc.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc);
-
- b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
- // Wifi is CONNECTING because the VPN isn't up yet.
- b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTING);
- ExpectedBroadcast b3 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
- mWiFiNetworkAgent.connect(false /* validated */);
- b1.expectBroadcast();
- b2.expectBroadcast();
- b3.expectBroadcast();
- mMockVpn.expectStopVpnRunnerPrivileged();
- mMockVpn.expectStartLegacyVpnRunner();
-
- // TODO: why is wifi not blocked? Is it because when this callback is sent, the VPN is still
- // connected, so the network is not considered blocked by the lockdown UID ranges? But the
- // fact that a VPN is connected should only result in the VPN itself being unblocked, not
- // any other network. Bug in isUidBlockedByVpn?
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
- systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // While the VPN is reconnecting on the new network, everything is blocked.
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mWiFiNetworkAgent);
-
- // The VPN comes up again on wifi.
- b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
- b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- establishLegacyLockdownVpn(mWiFiNetworkAgent.getNetwork());
- callback.expectAvailableThenValidatedCallbacks(mMockVpn);
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- systemDefaultCallback.assertNoCallback();
- b1.expectBroadcast();
- b2.expectBroadcast();
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mWiFiNetworkAgent);
- vpnNc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(vpnNc.hasTransport(TRANSPORT_VPN));
- assertTrue(vpnNc.hasTransport(TRANSPORT_WIFI));
- assertFalse(vpnNc.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(vpnNc.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- // Disconnect cell. Nothing much happens since it's not the default network.
- mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.assertNoCallback();
- systemDefaultCallback.assertNoCallback();
-
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mWiFiNetworkAgent);
-
- b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
- b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- b1.expectBroadcast();
- callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
- mMockVpn.expectStopVpnRunnerPrivileged();
- callback.expectCallback(CallbackEntry.LOST, mMockVpn);
- b2.expectBroadcast();
- }
-
- /**
- * Test mutable and requestable network capabilities such as
- * {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED} and
- * {@link NetworkCapabilities#NET_CAPABILITY_NOT_VCN_MANAGED}. Verify that the
- * {@code ConnectivityService} re-assign the networks accordingly.
- */
- @Test
- public final void testLoseMutableAndRequestableCaps() throws Exception {
- final int[] testCaps = new int [] {
- NET_CAPABILITY_TRUSTED,
- NET_CAPABILITY_NOT_VCN_MANAGED
- };
- for (final int testCap : testCaps) {
- // Create requests with and without the testing capability.
- final TestNetworkCallback callbackWithCap = new TestNetworkCallback();
- final TestNetworkCallback callbackWithoutCap = new TestNetworkCallback();
- mCm.requestNetwork(new NetworkRequest.Builder().addCapability(testCap).build(),
- callbackWithCap);
- mCm.requestNetwork(new NetworkRequest.Builder().removeCapability(testCap).build(),
- callbackWithoutCap);
-
- // Setup networks with testing capability and verify the default network changes.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(testCap);
- mCellNetworkAgent.connect(true);
- callbackWithCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- callbackWithoutCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(testCap);
- mWiFiNetworkAgent.connect(true);
- callbackWithCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- callbackWithoutCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- verify(mMockNetd).networkSetDefault(eq(mWiFiNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
-
- // Remove the testing capability on wifi, verify the callback and default network
- // changes back to cellular.
- mWiFiNetworkAgent.removeCapability(testCap);
- callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
- callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
-
- mCellNetworkAgent.removeCapability(testCap);
- callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- callbackWithoutCap.assertNoCallback();
- verify(mMockNetd).networkClearDefault();
-
- mCm.unregisterNetworkCallback(callbackWithCap);
- mCm.unregisterNetworkCallback(callbackWithoutCap);
- }
- }
-
- @Test
- public final void testBatteryStatsNetworkType() throws Exception {
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName("cell0");
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
- cellLp.getInterfaceName(),
- new int[] { TRANSPORT_CELLULAR });
-
- final LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName("wifi0");
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
- wifiLp.getInterfaceName(),
- new int[] { TRANSPORT_WIFI });
-
- mCellNetworkAgent.disconnect();
- mWiFiNetworkAgent.disconnect();
-
- cellLp.setInterfaceName("wifi0");
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
- cellLp.getInterfaceName(),
- new int[] { TRANSPORT_CELLULAR });
- mCellNetworkAgent.disconnect();
- }
-
- /**
- * Make simulated InterfaceConfigParcel for Nat464Xlat to query clat lower layer info.
- */
- private InterfaceConfigurationParcel getClatInterfaceConfigParcel(LinkAddress la) {
- final InterfaceConfigurationParcel cfg = new InterfaceConfigurationParcel();
- cfg.hwAddr = "11:22:33:44:55:66";
- cfg.ipv4Addr = la.getAddress().getHostAddress();
- cfg.prefixLength = la.getPrefixLength();
- return cfg;
- }
-
- /**
- * Make expected stack link properties, copied from Nat464Xlat.
- */
- private LinkProperties makeClatLinkProperties(LinkAddress la) {
- LinkAddress clatAddress = la;
- LinkProperties stacked = new LinkProperties();
- stacked.setInterfaceName(CLAT_PREFIX + MOBILE_IFNAME);
- RouteInfo ipv4Default = new RouteInfo(
- new LinkAddress(Inet4Address.ANY, 0),
- clatAddress.getAddress(), CLAT_PREFIX + MOBILE_IFNAME);
- stacked.addRoute(ipv4Default);
- stacked.addLinkAddress(clatAddress);
- return stacked;
- }
-
- private Nat64PrefixEventParcel makeNat64PrefixEvent(final int netId, final int prefixOperation,
- final String prefixAddress, final int prefixLength) {
- final Nat64PrefixEventParcel event = new Nat64PrefixEventParcel();
- event.netId = netId;
- event.prefixOperation = prefixOperation;
- event.prefixAddress = prefixAddress;
- event.prefixLength = prefixLength;
- return event;
- }
-
- @Test
- public void testStackedLinkProperties() throws Exception {
- final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
- final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
- final String kNat64PrefixString = "2001:db8:64:64:64:64::";
- final IpPrefix kNat64Prefix = new IpPrefix(InetAddress.getByName(kNat64PrefixString), 96);
- final String kOtherNat64PrefixString = "64:ff9b::";
- final IpPrefix kOtherNat64Prefix = new IpPrefix(
- InetAddress.getByName(kOtherNat64PrefixString), 96);
- final RouteInfo defaultRoute = new RouteInfo((IpPrefix) null, myIpv6.getAddress(),
- MOBILE_IFNAME);
- final RouteInfo ipv6Subnet = new RouteInfo(myIpv6, null, MOBILE_IFNAME);
- final RouteInfo ipv4Subnet = new RouteInfo(myIpv4, null, MOBILE_IFNAME);
- final RouteInfo stackedDefault = new RouteInfo((IpPrefix) null, myIpv4.getAddress(),
- CLAT_PREFIX + MOBILE_IFNAME);
-
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- // Prepare ipv6 only link properties.
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- cellLp.addLinkAddress(myIpv6);
- cellLp.addRoute(defaultRoute);
- cellLp.addRoute(ipv6Subnet);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- reset(mMockDnsResolver);
- reset(mMockNetd);
-
- // Connect with ipv6 link properties. Expect prefix discovery to be started.
- mCellNetworkAgent.connect(true);
- final int cellNetId = mCellNetworkAgent.getNetwork().netId;
- waitForIdle();
-
- verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(cellNetId,
- INetd.PERMISSION_NONE));
- assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
- verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
- verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME);
- verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
- cellLp.getInterfaceName(),
- new int[] { TRANSPORT_CELLULAR });
-
- networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
-
- // Switching default network updates TCP buffer sizes.
- verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
- // Add an IPv4 address. Expect prefix discovery to be stopped. Netd doesn't tell us that
- // the NAT64 prefix was removed because one was never discovered.
- cellLp.addLinkAddress(myIpv4);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- assertRoutesAdded(cellNetId, ipv4Subnet);
- verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
-
- // Make sure BatteryStats was not told about any v4- interfaces, as none should have
- // come online yet.
- waitForIdle();
- verify(mDeps, never())
- .reportNetworkInterfaceForTransports(eq(mServiceContext), startsWith("v4-"), any());
-
- verifyNoMoreInteractions(mMockNetd);
- verifyNoMoreInteractions(mMockDnsResolver);
- reset(mMockNetd);
- reset(mMockDnsResolver);
- when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfigParcel(myIpv4));
-
- // Remove IPv4 address. Expect prefix discovery to be started again.
- cellLp.removeLinkAddress(myIpv4);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
- assertRoutesRemoved(cellNetId, ipv4Subnet);
-
- // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
- Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
- assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
- makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
- LinkProperties lpBeforeClat = networkCallback.expectCallback(
- CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp();
- assertEquals(0, lpBeforeClat.getStackedLinks().size());
- assertEquals(kNat64Prefix, lpBeforeClat.getNat64Prefix());
- verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
-
- // Clat iface comes up. Expect stacked link to be added.
- clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
- .getStackedLinks();
- assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
- assertRoutesAdded(cellNetId, stackedDefault);
- verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
- // Change trivial linkproperties and see if stacked link is preserved.
- cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
-
- List<LinkProperties> stackedLpsAfterChange =
- mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks();
- assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
- assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
-
- verify(mMockDnsResolver, times(1)).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(1, resolvrParams.servers.length);
- assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
-
- for (final LinkProperties stackedLp : stackedLpsAfterChange) {
- verify(mDeps).reportNetworkInterfaceForTransports(
- mServiceContext, stackedLp.getInterfaceName(),
- new int[] { TRANSPORT_CELLULAR });
- }
- reset(mMockNetd);
- when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfigParcel(myIpv4));
- // Change the NAT64 prefix without first removing it.
- // Expect clatd to be stopped and started with the new prefix.
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
- cellNetId, PREFIX_OPERATION_ADDED, kOtherNat64PrefixString, 96));
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 0);
- verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- assertRoutesRemoved(cellNetId, stackedDefault);
- verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
-
- verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kOtherNat64Prefix.toString());
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getNat64Prefix().equals(kOtherNat64Prefix));
- clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 1);
- assertRoutesAdded(cellNetId, stackedDefault);
- verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
- reset(mMockNetd);
-
- // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
- // linkproperties are cleaned up.
- cellLp.addLinkAddress(myIpv4);
- cellLp.addRoute(ipv4Subnet);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- assertRoutesAdded(cellNetId, ipv4Subnet);
- verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
-
- // As soon as stop is called, the linkproperties lose the stacked interface.
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
- LinkProperties expected = new LinkProperties(cellLp);
- expected.setNat64Prefix(kOtherNat64Prefix);
- assertEquals(expected, actualLpAfterIpv4);
- assertEquals(0, actualLpAfterIpv4.getStackedLinks().size());
- assertRoutesRemoved(cellNetId, stackedDefault);
-
- // The interface removed callback happens but has no effect after stop is called.
- clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
- networkCallback.assertNoCallback();
- verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
- verifyNoMoreInteractions(mMockNetd);
- verifyNoMoreInteractions(mMockDnsResolver);
- reset(mMockNetd);
- reset(mMockDnsResolver);
- when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfigParcel(myIpv4));
-
- // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
- cellNetId, PREFIX_OPERATION_REMOVED, kOtherNat64PrefixString, 96));
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getNat64Prefix() == null);
-
- // Remove IPv4 address and expect prefix discovery and clatd to be started again.
- cellLp.removeLinkAddress(myIpv4);
- cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
- cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- assertRoutesRemoved(cellNetId, ipv4Subnet); // Directly-connected routes auto-added.
- verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
- cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
-
- // Clat iface comes up. Expect stacked link to be added.
- clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null);
- assertRoutesAdded(cellNetId, stackedDefault);
- verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
-
- // NAT64 prefix is removed. Expect that clat is stopped.
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
- cellNetId, PREFIX_OPERATION_REMOVED, kNat64PrefixString, 96));
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
- assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault);
-
- // Stop has no effect because clat is already stopped.
- verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 0);
- verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
- verify(mMockNetd, times(1)).interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME);
- verifyNoMoreInteractions(mMockNetd);
- // Clean up.
- mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- networkCallback.assertNoCallback();
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- private void expectNat64PrefixChange(TestableNetworkCallback callback,
- TestNetworkAgentWrapper agent, IpPrefix prefix) {
- callback.expectLinkPropertiesThat(agent, x -> Objects.equals(x.getNat64Prefix(), prefix));
- }
-
- @Test
- public void testNat64PrefixMultipleSources() throws Exception {
- final String iface = "wlan0";
- final String pref64FromRaStr = "64:ff9b::";
- final String pref64FromDnsStr = "2001:db8:64::";
- final IpPrefix pref64FromRa = new IpPrefix(InetAddress.getByName(pref64FromRaStr), 96);
- final IpPrefix pref64FromDns = new IpPrefix(InetAddress.getByName(pref64FromDnsStr), 96);
- final IpPrefix newPref64FromRa = new IpPrefix("2001:db8:64:64:64:64::/96");
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- final LinkProperties baseLp = new LinkProperties();
- baseLp.setInterfaceName(iface);
- baseLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- baseLp.addDnsServer(InetAddress.getByName("2001:4860:4860::6464"));
-
- reset(mMockNetd, mMockDnsResolver);
- InOrder inOrder = inOrder(mMockNetd, mMockDnsResolver);
-
- // If a network already has a NAT64 prefix on connect, clatd is started immediately and
- // prefix discovery is never started.
- LinkProperties lp = new LinkProperties(baseLp);
- lp.setNat64Prefix(pref64FromRa);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
- mWiFiNetworkAgent.connect(false);
- final Network network = mWiFiNetworkAgent.getNetwork();
- int netId = network.getNetId();
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- callback.assertNoCallback();
- assertEquals(pref64FromRa, mCm.getLinkProperties(network).getNat64Prefix());
-
- // If the RA prefix is withdrawn, clatd is stopped and prefix discovery is started.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
-
- // If the RA prefix appears while DNS discovery is in progress, discovery is stopped and
- // clatd is started with the prefix from the RA.
- lp.setNat64Prefix(pref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
-
- // Withdraw the RA prefix so we can test the case where an RA prefix appears after DNS
- // discovery has succeeded.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
-
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
- makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96));
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
-
- // If an RA advertises the same prefix that was discovered by DNS, nothing happens: prefix
- // discovery is not stopped, and there are no callbacks.
- lp.setNat64Prefix(pref64FromDns);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // If the RA is later withdrawn, nothing happens again.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // If the RA prefix changes, clatd is restarted and prefix discovery is stopped.
- lp.setNat64Prefix(pref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
-
- // Stopping prefix discovery results in a prefix removed notification.
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
- makeNat64PrefixEvent(netId, PREFIX_OPERATION_REMOVED, pref64FromDnsStr, 96));
-
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
-
- // If the RA prefix changes, clatd is restarted and prefix discovery is not started.
- lp.setNat64Prefix(newPref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, newPref64FromRa);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockNetd).clatdStart(iface, newPref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, newPref64FromRa.toString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
-
- // If the RA prefix changes to the same value, nothing happens.
- lp.setNat64Prefix(newPref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- assertEquals(newPref64FromRa, mCm.getLinkProperties(network).getNat64Prefix());
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // The transition between no prefix and DNS prefix is tested in testStackedLinkProperties.
-
- // If the same prefix is learned first by DNS and then by RA, and clat is later stopped,
- // (e.g., because the network disconnects) setPrefix64(netid, "") is never called.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
- makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96));
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any());
-
- lp.setNat64Prefix(pref64FromDns);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // When tearing down a network, clat state is only updated after CALLBACK_LOST is fired, but
- // before CONNECTIVITY_ACTION is sent. Wait for CONNECTIVITY_ACTION before verifying that
- // clat has been stopped, or the test will be flaky.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- b.expectBroadcast();
-
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- mCm.unregisterNetworkCallback(callback);
- }
-
- @Test
- public void testWith464XlatDisable() throws Exception {
- doReturn(false).when(mDeps).getCellular464XlatEnabled();
-
- final TestNetworkCallback callback = new TestNetworkCallback();
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- mCm.registerNetworkCallback(networkRequest, callback);
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- // Bring up validated cell.
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, MOBILE_IFNAME));
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-
- mCellNetworkAgent.sendLinkProperties(cellLp);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- final int cellNetId = mCellNetworkAgent.getNetwork().netId;
- waitForIdle();
-
- verify(mMockDnsResolver, never()).startPrefix64Discovery(cellNetId);
- Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
- assertTrue("Nat464Xlat was not IDLE", !clat.isStarted());
-
- // This cannot happen because prefix discovery cannot succeed if it is never started.
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
- makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, "64:ff9b::", 96));
-
- // ... but still, check that even if it did, clatd would not be started.
- verify(mMockNetd, never()).clatdStart(anyString(), anyString());
- assertTrue("Nat464Xlat was not IDLE", !clat.isStarted());
- }
-
- @Test
- public void testDataActivityTracking() throws Exception {
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- mCellNetworkAgent.connect(true);
- networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName(WIFI_IFNAME);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
-
- // Network switch
- mWiFiNetworkAgent.connect(true);
- networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
- verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
-
- // Disconnect wifi and switch back to cell
- reset(mMockNetd);
- mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- assertNoCallbacks(networkCallback);
- verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
- verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
-
- // reconnect wifi
- reset(mMockNetd);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- wifiLp.setInterfaceName(WIFI_IFNAME);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- mWiFiNetworkAgent.connect(true);
- networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
- verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
-
- // Disconnect cell
- reset(mMockNetd);
- mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- // LOST callback is triggered earlier than removing idle timer. Broadcast should also be
- // sent as network being switched. Ensure rule removal for cell will not be triggered
- // unexpectedly before network being removed.
- waitForIdle();
- verify(mMockNetd, times(0)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
- verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
- verify(mMockDnsResolver, times(1))
- .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
-
- // Disconnect wifi
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
-
- // Clean up
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- private void verifyTcpBufferSizeChange(String tcpBufferSizes) throws Exception {
- String[] values = tcpBufferSizes.split(",");
- String rmemValues = String.join(" ", values[0], values[1], values[2]);
- String wmemValues = String.join(" ", values[3], values[4], values[5]);
- verify(mMockNetd, atLeastOnce()).setTcpRWmemorySize(rmemValues, wmemValues);
- reset(mMockNetd);
- }
-
- @Test
- public void testTcpBufferReset() throws Exception {
- final String testTcpBufferSizes = "1,2,3,4,5,6";
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- reset(mMockNetd);
- // Switching default network updates TCP buffer sizes.
- mCellNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
- // Change link Properties should have updated tcp buffer size.
- LinkProperties lp = new LinkProperties();
- lp.setTcpBufferSizes(testTcpBufferSizes);
- mCellNetworkAgent.sendLinkProperties(lp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- verifyTcpBufferSizeChange(testTcpBufferSizes);
- // Clean up.
- mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- networkCallback.assertNoCallback();
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- @Test
- public void testGetGlobalProxyForNetwork() throws Exception {
- final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
- when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo);
- assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork));
- }
-
- @Test
- public void testGetProxyForActiveNetwork() throws Exception {
- final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(null));
-
- final LinkProperties testLinkProperties = new LinkProperties();
- testLinkProperties.setHttpProxy(testProxyInfo);
-
- mWiFiNetworkAgent.sendLinkProperties(testLinkProperties);
- waitForIdle();
-
- assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
- }
-
- @Test
- public void testGetProxyForVPN() throws Exception {
- final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
-
- // Set up a WiFi network with no proxy
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(null));
-
- // Connect a VPN network with a proxy.
- LinkProperties testLinkProperties = new LinkProperties();
- testLinkProperties.setHttpProxy(testProxyInfo);
- mMockVpn.establishForMyUid(testLinkProperties);
- assertUidRangesUpdatedForMyUid(true);
-
- // Test that the VPN network returns a proxy, and the WiFi does not.
- assertEquals(testProxyInfo, mService.getProxyForNetwork(mMockVpn.getNetwork()));
- assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
- assertNull(mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
-
- // Test that the VPN network returns no proxy when it is set to null.
- testLinkProperties.setHttpProxy(null);
- mMockVpn.sendLinkProperties(testLinkProperties);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(mMockVpn.getNetwork()));
- assertNull(mService.getProxyForNetwork(null));
-
- // Set WiFi proxy and check that the vpn proxy is still null.
- testLinkProperties.setHttpProxy(testProxyInfo);
- mWiFiNetworkAgent.sendLinkProperties(testLinkProperties);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(null));
-
- // Disconnect from VPN and check that the active network, which is now the WiFi, has the
- // correct proxy setting.
- mMockVpn.disconnect();
- waitForIdle();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
- assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
- }
-
- @Test
- public void testFullyRoutedVpnResultsInInterfaceFilteringRules() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.establish(lp, VPN_UID, vpnRange);
- assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
-
- // A connected VPN should have interface rules set up. There are two expected invocations,
- // one during the VPN initial connection, one during the VPN LinkProperties update.
- ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
- verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
- assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID);
- assertTrue(mService.mPermissionMonitor.getVpnUidRanges("tun0").equals(vpnRange));
-
- mMockVpn.disconnect();
- waitForIdle();
-
- // Disconnected VPN should have interface rules removed
- verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- assertNull(mService.mPermissionMonitor.getVpnUidRanges("tun0"));
- }
-
- @Test
- public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
- assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
-
- // Legacy VPN should not have interface rules set up
- verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
- }
-
- @Test
- public void testLocalIpv4OnlyVpnDoesNotResultInInterfaceFilteringRule()
- throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
- assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
-
- // IPv6 unreachable route should not be misinterpreted as a default route
- verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
- }
-
- @Test
- public void testVpnHandoverChangesInterfaceFilteringRule() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.establish(lp, VPN_UID, vpnRange);
- assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
-
- // Connected VPN should have interface rules set up. There are two expected invocations,
- // one during VPN uid update, one during VPN LinkProperties update
- ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
- verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
- assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID);
-
- reset(mMockNetd);
- InOrder inOrder = inOrder(mMockNetd);
- lp.setInterfaceName("tun1");
- mMockVpn.sendLinkProperties(lp);
- waitForIdle();
- // VPN handover (switch to a new interface) should result in rules being updated (old rules
- // removed first, then new rules added)
- inOrder.verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- inOrder.verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
-
- reset(mMockNetd);
- lp = new LinkProperties();
- lp.setInterfaceName("tun1");
- lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun1"));
- mMockVpn.sendLinkProperties(lp);
- waitForIdle();
- // VPN not routing everything should no longer have interface filtering rules
- verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
-
- reset(mMockNetd);
- lp = new LinkProperties();
- lp.setInterfaceName("tun1");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- mMockVpn.sendLinkProperties(lp);
- waitForIdle();
- // Back to routing all IPv6 traffic should have filtering rules
- verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- }
-
- @Test
- public void testUidUpdateChangesInterfaceFilteringRule() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- // The uid range needs to cover the test app so the network is visible to it.
- final UidRange vpnRange = PRIMARY_UIDRANGE;
- final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
- mMockVpn.establish(lp, VPN_UID, vpnRanges);
- assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
-
- reset(mMockNetd);
- InOrder inOrder = inOrder(mMockNetd);
-
- // Update to new range which is old range minus APP1, i.e. only APP2
- final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
- new UidRange(vpnRange.start, APP1_UID - 1),
- new UidRange(APP1_UID + 1, vpnRange.stop)));
- mMockVpn.setUids(newRanges);
- waitForIdle();
-
- ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
- // Verify old rules are removed before new rules are added
- inOrder.verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- inOrder.verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP2_UID);
- }
-
- @Test
- public void testLinkPropertiesWithWakeOnLanForActiveNetwork() throws Exception {
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName(WIFI_WOL_IFNAME);
- wifiLp.setWakeOnLanSupported(false);
-
- // Default network switch should update ifaces.
- mWiFiNetworkAgent.connect(false);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- waitForIdle();
-
- // ConnectivityService should have changed the WakeOnLanSupported to true
- wifiLp.setWakeOnLanSupported(true);
- assertEquals(wifiLp, mService.getActiveLinkProperties());
- }
-
- @Test
- public void testLegacyExtraInfoSentToNetworkMonitor() throws Exception {
- class TestNetworkAgent extends NetworkAgent {
- TestNetworkAgent(Context context, Looper looper, NetworkAgentConfig config) {
- super(context, looper, "MockAgent", new NetworkCapabilities(),
- new LinkProperties(), 40 , config, null /* provider */);
- }
- }
- final NetworkAgent naNoExtraInfo = new TestNetworkAgent(
- mServiceContext, mCsHandlerThread.getLooper(), new NetworkAgentConfig());
- naNoExtraInfo.register();
- verify(mNetworkStack).makeNetworkMonitor(any(), isNull(String.class), any());
- naNoExtraInfo.unregister();
-
- reset(mNetworkStack);
- final NetworkAgentConfig config =
- new NetworkAgentConfig.Builder().setLegacyExtraInfo("legacyinfo").build();
- final NetworkAgent naExtraInfo = new TestNetworkAgent(
- mServiceContext, mCsHandlerThread.getLooper(), config);
- naExtraInfo.register();
- verify(mNetworkStack).makeNetworkMonitor(any(), eq("legacyinfo"), any());
- naExtraInfo.unregister();
- }
-
- // To avoid granting location permission bypass.
- private void denyAllLocationPrivilegedPermissions() {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_DENIED);
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_STACK,
- PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
- PERMISSION_DENIED);
- }
-
- private void setupLocationPermissions(
- int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
- denyAllLocationPrivilegedPermissions();
-
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = targetSdk;
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
- .thenReturn(applicationInfo);
- when(mPackageManager.getTargetSdkVersion(any())).thenReturn(targetSdk);
-
- when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
-
- if (op != null) {
- when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()),
- eq(mContext.getPackageName()), eq(getAttributionTag()), anyString()))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
- }
-
- if (perm != null) {
- mServiceContext.setPermission(perm, PERMISSION_GRANTED);
- }
- }
-
- private int getOwnerUidNetCapsPermission(int ownerUid, int callerUid,
- boolean includeLocationSensitiveInfo) {
- final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
-
- return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, includeLocationSensitiveInfo, Process.myUid(), callerUid,
- mContext.getPackageName(), getAttributionTag())
- .getOwnerUid();
- }
-
- private void verifyTransportInfoCopyNetCapsPermission(
- int callerUid, boolean includeLocationSensitiveInfo,
- boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
- final TransportInfo transportInfo = mock(TransportInfo.class);
- when(transportInfo.getApplicableRedactions()).thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION);
- final NetworkCapabilities netCap =
- new NetworkCapabilities().setTransportInfo(transportInfo);
-
- mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, includeLocationSensitiveInfo, Process.myPid(), callerUid,
- mContext.getPackageName(), getAttributionTag());
- if (shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
- verify(transportInfo).makeCopy(REDACT_NONE);
- } else {
- verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
- }
- }
-
- private void verifyOwnerUidAndTransportInfoNetCapsPermission(
- boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag,
- boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag,
- boolean shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag,
- boolean shouldInclLocationSensitiveTransportInfoWithIncludeFlag) {
- final int myUid = Process.myUid();
-
- final int expectedOwnerUidWithoutIncludeFlag =
- shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag
- ? myUid : INVALID_UID;
- assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission(
- myUid, myUid, false /* includeLocationSensitiveInfo */));
-
- final int expectedOwnerUidWithIncludeFlag =
- shouldInclLocationSensitiveOwnerUidWithIncludeFlag ? myUid : INVALID_UID;
- assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission(
- myUid, myUid, true /* includeLocationSensitiveInfo */));
-
- verifyTransportInfoCopyNetCapsPermission(myUid,
- false, /* includeLocationSensitiveInfo */
- shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag);
-
- verifyTransportInfoCopyNetCapsPermission(myUid,
- true, /* includeLocationSensitiveInfo */
- shouldInclLocationSensitiveTransportInfoWithIncludeFlag);
-
- }
-
- private void verifyOwnerUidAndTransportInfoNetCapsPermissionPreS() {
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that owner uid is included even if the request asks to remove it (which is
- // the default) since the app has necessary permissions and targetSdk < S.
- true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- // Ensure that location info is removed if the request asks to remove it even if the
- // app has necessary permissions.
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQPreS()
- throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWithFineLocationPreSWithAndWithoutCallbackFlag()
- throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
- }
-
- @Test
- public void
- testCreateWithLocationInfoSanitizedWithFineLocationAfterSWithAndWithoutCallbackFlag()
- throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that the owner UID is removed if the request asks us to remove it even
- // if the app has necessary permissions since targetSdk >= S.
- false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- // Ensure that location info is removed if the request asks to remove it even if the
- // app has necessary permissions.
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWithCoarseLocationPreQ()
- throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
- }
-
- private void verifyOwnerUidAndTransportInfoNetCapsNotIncluded() {
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedLocationOff() throws Exception {
- // Test that even with fine location permission, and UIDs matching, the UID is sanitized.
- setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWrongUid() throws Exception {
- // Test that even with fine location permission, not being the owner leads to sanitization.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID,
- getOwnerUidNetCapsPermission(myUid + 1, myUid,
- true /* includeLocationSensitiveInfo */));
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterQ()
- throws Exception {
- // Test that not having fine location permission leads to sanitization.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterS()
- throws Exception {
- // Test that not having fine location permission leads to sanitization.
- setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_COARSE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
- }
-
- @Test
- public void testCreateForCallerWithLocalMacAddressSanitizedWithLocalMacAddressPermission()
- throws Exception {
- mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_GRANTED);
-
- final TransportInfo transportInfo = mock(TransportInfo.class);
- when(transportInfo.getApplicableRedactions())
- .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
- final NetworkCapabilities netCap =
- new NetworkCapabilities().setTransportInfo(transportInfo);
-
- mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
- Process.myPid(), Process.myUid(),
- mContext.getPackageName(), getAttributionTag());
- // don't redact MAC_ADDRESS fields, only location sensitive fields.
- verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
- }
-
- @Test
- public void testCreateForCallerWithLocalMacAddressSanitizedWithoutLocalMacAddressPermission()
- throws Exception {
- mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
-
- final TransportInfo transportInfo = mock(TransportInfo.class);
- when(transportInfo.getApplicableRedactions())
- .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
- final NetworkCapabilities netCap =
- new NetworkCapabilities().setTransportInfo(transportInfo);
-
- mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
- Process.myPid(), Process.myUid(),
- mContext.getPackageName(), getAttributionTag());
- // redact both MAC_ADDRESS & location sensitive fields.
- verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION
- | REDACT_FOR_LOCAL_MAC_ADDRESS);
- }
-
- @Test
- public void testCreateForCallerWithLocalMacAddressSanitizedWithSettingsPermission()
- throws Exception {
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TransportInfo transportInfo = mock(TransportInfo.class);
- when(transportInfo.getApplicableRedactions())
- .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
- final NetworkCapabilities netCap =
- new NetworkCapabilities().setTransportInfo(transportInfo);
-
- mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
- Process.myPid(), Process.myUid(),
- mContext.getPackageName(), getAttributionTag());
- // don't redact NETWORK_SETTINGS fields, only location sensitive fields.
- verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
- }
-
- @Test
- public void testCreateForCallerWithLocalMacAddressSanitizedWithoutSettingsPermission()
- throws Exception {
- mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
-
- final TransportInfo transportInfo = mock(TransportInfo.class);
- when(transportInfo.getApplicableRedactions())
- .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
- final NetworkCapabilities netCap =
- new NetworkCapabilities().setTransportInfo(transportInfo);
-
- mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
- Process.myPid(), Process.myUid(),
- mContext.getPackageName(), getAttributionTag());
- // redact both NETWORK_SETTINGS & location sensitive fields.
- verify(transportInfo).makeCopy(
- REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
- }
-
- /**
- * Test TransportInfo to verify redaction mechanism.
- */
- private static class TestTransportInfo implements TransportInfo {
- public final boolean locationRedacted;
- public final boolean localMacAddressRedacted;
- public final boolean settingsRedacted;
-
- TestTransportInfo() {
- locationRedacted = false;
- localMacAddressRedacted = false;
- settingsRedacted = false;
- }
-
- TestTransportInfo(boolean locationRedacted, boolean localMacAddressRedacted,
- boolean settingsRedacted) {
- this.locationRedacted = locationRedacted;
- this.localMacAddressRedacted =
- localMacAddressRedacted;
- this.settingsRedacted = settingsRedacted;
- }
-
- @Override
- public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
- return new TestTransportInfo(
- locationRedacted | (redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
- localMacAddressRedacted | (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
- settingsRedacted | (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
- );
- }
-
- @Override
- public @NetworkCapabilities.RedactionType long getApplicableRedactions() {
- return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
- | REDACT_FOR_NETWORK_SETTINGS;
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof TestTransportInfo)) return false;
- TestTransportInfo that = (TestTransportInfo) other;
- return that.locationRedacted == this.locationRedacted
- && that.localMacAddressRedacted == this.localMacAddressRedacted
- && that.settingsRedacted == this.settingsRedacted;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(locationRedacted, localMacAddressRedacted, settingsRedacted);
- }
-
- @Override
- public String toString() {
- return String.format(
- "TestTransportInfo{locationRedacted=%s macRedacted=%s settingsRedacted=%s}",
- locationRedacted, localMacAddressRedacted, settingsRedacted);
- }
- }
-
- private TestTransportInfo getTestTransportInfo(NetworkCapabilities nc) {
- return (TestTransportInfo) nc.getTransportInfo();
- }
-
- private TestTransportInfo getTestTransportInfo(TestNetworkAgentWrapper n) {
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(n.getNetwork());
- assertNotNull(nc);
- return getTestTransportInfo(nc);
- }
-
-
- private void verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
- @NonNull TestNetworkCallback wifiNetworkCallback, int actualOwnerUid,
- @NonNull TransportInfo actualTransportInfo, int expectedOwnerUid,
- @NonNull TransportInfo expectedTransportInfo) throws Exception {
- when(mPackageManager.getTargetSdkVersion(anyString())).thenReturn(Build.VERSION_CODES.S);
- final NetworkCapabilities ncTemplate =
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .setOwnerUid(actualOwnerUid);
-
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
- ncTemplate);
- mWiFiNetworkAgent.connect(false);
-
- wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Send network capabilities update with TransportInfo to trigger capabilities changed
- // callback.
- mWiFiNetworkAgent.setNetworkCapabilities(
- ncTemplate.setTransportInfo(actualTransportInfo), true);
-
- wifiNetworkCallback.expectCapabilitiesThat(mWiFiNetworkAgent,
- nc -> Objects.equals(expectedOwnerUid, nc.getOwnerUid())
- && Objects.equals(expectedTransportInfo, nc.getTransportInfo()));
- }
-
- @Test
- public void testVerifyLocationDataIsNotIncludedWhenInclFlagNotSet() throws Exception {
- final TestNetworkCallback wifiNetworkCallack = new TestNetworkCallback();
- final int ownerUid = Process.myUid();
- final TransportInfo transportInfo = new TestTransportInfo();
- // Even though the test uid holds privileged permissions, mask location fields since
- // the callback did not explicitly opt-in to get location data.
- final TransportInfo sanitizedTransportInfo = new TestTransportInfo(
- true, /* locationRedacted */
- true, /* localMacAddressRedacted */
- true /* settingsRedacted */
- );
- // Should not expect location data since the callback does not set the flag for including
- // location data.
- verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
- wifiNetworkCallack, ownerUid, transportInfo, INVALID_UID, sanitizedTransportInfo);
- }
-
- @Test
- public void testTransportInfoRedactionInSynchronousCalls() throws Exception {
- final NetworkCapabilities ncTemplate = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .setTransportInfo(new TestTransportInfo());
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
- ncTemplate);
- mWiFiNetworkAgent.connect(true /* validated; waits for callback */);
-
- // NETWORK_SETTINGS redaction is controlled by the NETWORK_SETTINGS permission
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted);
- withPermission(NETWORK_SETTINGS, () -> {
- assertFalse(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted);
- });
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted);
-
- // LOCAL_MAC_ADDRESS redaction is controlled by the LOCAL_MAC_ADDRESS permission
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted);
- withPermission(LOCAL_MAC_ADDRESS, () -> {
- assertFalse(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted);
- });
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted);
-
- // Synchronous getNetworkCapabilities calls never return unredacted location-sensitive
- // information.
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted);
- setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted);
- denyAllLocationPrivilegedPermissions();
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted);
- }
-
- private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
- throws Exception {
- final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.setVpnType(vpnType);
- mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
- assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
-
- final UnderlyingNetworkInfo underlyingNetworkInfo =
- new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<String>());
- mMockVpn.setUnderlyingNetworkInfo(underlyingNetworkInfo);
- when(mDeps.getConnectionOwnerUid(anyInt(), any(), any())).thenReturn(42);
- }
-
- private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
- throws Exception {
- setupConnectionOwnerUid(vpnOwnerUid, vpnType);
-
- // Test as VPN app
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
- mServiceContext.setPermission(
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_DENIED);
- }
-
- private ConnectionInfo getTestConnectionInfo() throws Exception {
- return new ConnectionInfo(
- IPPROTO_TCP,
- new InetSocketAddress(InetAddresses.parseNumericAddress("1.2.3.4"), 1234),
- new InetSocketAddress(InetAddresses.parseNumericAddress("2.3.4.5"), 2345));
- }
-
- @Test
- public void testGetConnectionOwnerUidPlatformVpn() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUidAsVpnApp(myUid, VpnManager.TYPE_VPN_PLATFORM);
-
- assertEquals(INVALID_UID, mService.getConnectionOwnerUid(getTestConnectionInfo()));
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceWrongUser() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUidAsVpnApp(myUid + 1, VpnManager.TYPE_VPN_SERVICE);
-
- assertEquals(INVALID_UID, mService.getConnectionOwnerUid(getTestConnectionInfo()));
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceDoesNotThrow() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUidAsVpnApp(myUid, VpnManager.TYPE_VPN_SERVICE);
-
- assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceNetworkStackDoesNotThrow() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUid(myUid, VpnManager.TYPE_VPN_SERVICE);
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
-
- assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceMainlineNetworkStackDoesNotThrow()
- throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUid(myUid, VpnManager.TYPE_VPN_SERVICE);
- mServiceContext.setPermission(
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_GRANTED);
-
- assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
- }
-
- private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid) {
- final PackageInfo packageInfo = new PackageInfo();
- if (hasSystemPermission) {
- packageInfo.requestedPermissions = new String[] {
- CHANGE_NETWORK_STATE, CONNECTIVITY_USE_RESTRICTED_NETWORKS };
- packageInfo.requestedPermissionsFlags = new int[] {
- REQUESTED_PERMISSION_GRANTED, REQUESTED_PERMISSION_GRANTED };
- } else {
- packageInfo.requestedPermissions = new String[0];
- }
- packageInfo.applicationInfo = new ApplicationInfo();
- packageInfo.applicationInfo.privateFlags = 0;
- packageInfo.applicationInfo.uid = UserHandle.getUid(UserHandle.USER_SYSTEM,
- UserHandle.getAppId(uid));
- return packageInfo;
- }
-
- @Test
- public void testRegisterConnectivityDiagnosticsCallbackInvalidRequest() throws Exception {
- final NetworkRequest request =
- new NetworkRequest(
- new NetworkCapabilities(), TYPE_ETHERNET, 0, NetworkRequest.Type.NONE);
- try {
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
- fail("registerConnectivityDiagnosticsCallback should throw on invalid NetworkRequest");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- private void assertRouteInfoParcelMatches(RouteInfo route, RouteInfoParcel parcel) {
- assertEquals(route.getDestination().toString(), parcel.destination);
- assertEquals(route.getInterface(), parcel.ifName);
- assertEquals(route.getMtu(), parcel.mtu);
-
- switch (route.getType()) {
- case RouteInfo.RTN_UNICAST:
- if (route.hasGateway()) {
- assertEquals(route.getGateway().getHostAddress(), parcel.nextHop);
- } else {
- assertEquals(INetd.NEXTHOP_NONE, parcel.nextHop);
- }
- break;
- case RouteInfo.RTN_UNREACHABLE:
- assertEquals(INetd.NEXTHOP_UNREACHABLE, parcel.nextHop);
- break;
- case RouteInfo.RTN_THROW:
- assertEquals(INetd.NEXTHOP_THROW, parcel.nextHop);
- break;
- default:
- assertEquals(INetd.NEXTHOP_NONE, parcel.nextHop);
- break;
- }
- }
-
- private void assertRoutesAdded(int netId, RouteInfo... routes) throws Exception {
- ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
- verify(mMockNetd, times(routes.length)).networkAddRouteParcel(eq(netId), captor.capture());
- for (int i = 0; i < routes.length; i++) {
- assertRouteInfoParcelMatches(routes[i], captor.getAllValues().get(i));
- }
- }
-
- private void assertRoutesRemoved(int netId, RouteInfo... routes) throws Exception {
- ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
- verify(mMockNetd, times(routes.length)).networkRemoveRouteParcel(eq(netId),
- captor.capture());
- for (int i = 0; i < routes.length; i++) {
- assertRouteInfoParcelMatches(routes[i], captor.getAllValues().get(i));
- }
- }
-
- @Test
- public void testRegisterUnregisterConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest wifiRequest =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
- verify(mConnectivityDiagnosticsCallback).asBinder();
- assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
-
- mService.unregisterConnectivityDiagnosticsCallback(mConnectivityDiagnosticsCallback);
- verify(mIBinder, timeout(TIMEOUT_MS))
- .unlinkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
- assertFalse(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
- verify(mConnectivityDiagnosticsCallback, atLeastOnce()).asBinder();
- }
-
- @Test
- public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest wifiRequest =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
- verify(mConnectivityDiagnosticsCallback).asBinder();
- assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
-
- // Register the same callback again
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
- }
-
- public NetworkAgentInfo fakeMobileNai(NetworkCapabilities nc) {
- final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE,
- ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
- TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
- return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
- nc, new NetworkScore.Builder().setLegacyInt(0).build(),
- mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
- INVALID_UID, TEST_LINGER_DELAY_MS, mQosCallbackTracker,
- new ConnectivityService.Dependencies());
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
- final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
-
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
- assertTrue(
- "NetworkStack permission not applied",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception {
- final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
-
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- assertFalse(
- "Mismatched uid/package name should not pass the location permission check",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid() + 1, Process.myUid() + 1, naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
- final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
-
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- assertFalse(
- "ACCESS_FINE_LOCATION permission necessary for Connectivity Diagnostics",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
- final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
-
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
-
- // Wait for networks to connect and broadcasts to be sent before removing permissions.
- waitForIdle();
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- assertTrue(mMockVpn.setUnderlyingNetworks(new Network[] {naiWithoutUid.network}));
- waitForIdle();
- assertTrue(
- "Active VPN permission not applied",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
-
- assertTrue(mMockVpn.setUnderlyingNetworks(null));
- waitForIdle();
- assertFalse(
- "VPN shouldn't receive callback on non-underlying network",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception {
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setAdministratorUids(new int[] {Process.myUid()});
- final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
-
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- assertTrue(
- "NetworkCapabilities administrator uid permission not applied",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithUid, mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsFails() throws Exception {
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setOwnerUid(Process.myUid());
- nc.setAdministratorUids(new int[] {Process.myUid()});
- final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
-
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- // Use wrong pid and uid
- assertFalse(
- "Permissions allowed when they shouldn't be granted",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid() + 1, Process.myUid() + 1, naiWithUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testRegisterConnectivityDiagnosticsCallbackCallsOnConnectivityReport()
- throws Exception {
- // Set up the Network, which leads to a ConnectivityReport being cached for the network.
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(INTERFACE_NAME);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, linkProperties);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- callback.assertNoCallback();
-
- final NetworkRequest request = new NetworkRequest.Builder().build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- verify(mConnectivityDiagnosticsCallback)
- .onConnectivityReportAvailable(argThat(report -> {
- return INTERFACE_NAME.equals(report.getLinkProperties().getInterfaceName())
- && report.getNetworkCapabilities().hasTransport(TRANSPORT_CELLULAR);
- }));
- }
-
- private void setUpConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Connect the cell agent verify that it notifies TestNetworkCallback that it is available
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
-
- final NetworkCapabilities ncTemplate = new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .setTransportInfo(new TestTransportInfo());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(),
- ncTemplate);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- callback.assertNoCallback();
- }
-
- private boolean areConnDiagCapsRedacted(NetworkCapabilities nc) {
- TestTransportInfo ti = (TestTransportInfo) nc.getTransportInfo();
- return nc.getUids() == null
- && nc.getAdministratorUids().length == 0
- && nc.getOwnerUid() == Process.INVALID_UID
- && getTestTransportInfo(nc).locationRedacted
- && getTestTransportInfo(nc).localMacAddressRedacted
- && getTestTransportInfo(nc).settingsRedacted;
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnConnectivityReportAvailable()
- throws Exception {
- setUpConnectivityDiagnosticsCallback();
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Verify onConnectivityReport fired
- verify(mConnectivityDiagnosticsCallback).onConnectivityReportAvailable(
- argThat(report -> areConnDiagCapsRedacted(report.getNetworkCapabilities())));
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnDataStallSuspected() throws Exception {
- setUpConnectivityDiagnosticsCallback();
-
- // Trigger notifyDataStallSuspected() on the INetworkMonitorCallbacks instance in the
- // cellular network agent
- mCellNetworkAgent.notifyDataStallSuspected();
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Verify onDataStallSuspected fired
- verify(mConnectivityDiagnosticsCallback).onDataStallSuspected(
- argThat(report -> areConnDiagCapsRedacted(report.getNetworkCapabilities())));
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnConnectivityReported() throws Exception {
- setUpConnectivityDiagnosticsCallback();
-
- final Network n = mCellNetworkAgent.getNetwork();
- final boolean hasConnectivity = true;
- mService.reportNetworkConnectivity(n, hasConnectivity);
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Verify onNetworkConnectivityReported fired
- verify(mConnectivityDiagnosticsCallback)
- .onNetworkConnectivityReported(eq(n), eq(hasConnectivity));
-
- final boolean noConnectivity = false;
- mService.reportNetworkConnectivity(n, noConnectivity);
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Wait for onNetworkConnectivityReported to fire
- verify(mConnectivityDiagnosticsCallback)
- .onNetworkConnectivityReported(eq(n), eq(noConnectivity));
- }
-
- @Test
- public void testRouteAddDeleteUpdate() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, networkCallback);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- reset(mMockNetd);
- mCellNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- final int netId = mCellNetworkAgent.getNetwork().netId;
-
- final String iface = "rmnet_data0";
- final InetAddress gateway = InetAddress.getByName("fe80::5678");
- RouteInfo direct = RouteInfo.makeHostRoute(gateway, iface);
- RouteInfo rio1 = new RouteInfo(new IpPrefix("2001:db8:1::/48"), gateway, iface);
- RouteInfo rio2 = new RouteInfo(new IpPrefix("2001:db8:2::/48"), gateway, iface);
- RouteInfo defaultRoute = new RouteInfo((IpPrefix) null, gateway, iface);
- RouteInfo defaultWithMtu = new RouteInfo(null, gateway, iface, RouteInfo.RTN_UNICAST,
- 1280 /* mtu */);
-
- // Send LinkProperties and check that we ask netd to add routes.
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(iface);
- lp.addRoute(direct);
- lp.addRoute(rio1);
- lp.addRoute(defaultRoute);
- mCellNetworkAgent.sendLinkProperties(lp);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, x -> x.getRoutes().size() == 3);
-
- assertRoutesAdded(netId, direct, rio1, defaultRoute);
- reset(mMockNetd);
-
- // Send updated LinkProperties and check that we ask netd to add, remove, update routes.
- assertTrue(lp.getRoutes().contains(defaultRoute));
- lp.removeRoute(rio1);
- lp.addRoute(rio2);
- lp.addRoute(defaultWithMtu);
- // Ensure adding the same route with a different MTU replaces the previous route.
- assertFalse(lp.getRoutes().contains(defaultRoute));
- assertTrue(lp.getRoutes().contains(defaultWithMtu));
-
- mCellNetworkAgent.sendLinkProperties(lp);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- x -> x.getRoutes().contains(rio2));
-
- assertRoutesRemoved(netId, rio1);
- assertRoutesAdded(netId, rio2);
-
- ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
- verify(mMockNetd).networkUpdateRouteParcel(eq(netId), captor.capture());
- assertRouteInfoParcelMatches(defaultWithMtu, captor.getValue());
-
-
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- @Test
- public void testDumpDoesNotCrash() {
- mServiceContext.setPermission(DUMP, PERMISSION_GRANTED);
- // Filing a couple requests prior to testing the dump.
- final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
- final NetworkRequest genericRequest = new NetworkRequest.Builder()
- .clearCapabilities().build();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
- final StringWriter stringWriter = new StringWriter();
-
- mService.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
-
- assertFalse(stringWriter.toString().isEmpty());
- }
-
- @Test
- public void testRequestsSortedByIdSortsCorrectly() {
- final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest genericRequest = new NetworkRequest.Builder()
- .clearCapabilities().build();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
- waitForIdle();
-
- final ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
-
- assertTrue(nriOutput.length > 1);
- for (int i = 0; i < nriOutput.length - 1; i++) {
- final boolean isRequestIdInOrder =
- nriOutput[i].mRequests.get(0).requestId
- < nriOutput[i + 1].mRequests.get(0).requestId;
- assertTrue(isRequestIdInOrder);
- }
- }
-
- private void assertUidRangesUpdatedForMyUid(boolean add) throws Exception {
- final int uid = Process.myUid();
- assertVpnUidRangesUpdated(add, uidRangesForUids(uid), uid);
- }
-
- private void assertVpnUidRangesUpdated(boolean add, Set<UidRange> vpnRanges, int exemptUid)
- throws Exception {
- InOrder inOrder = inOrder(mMockNetd);
- ArgumentCaptor<int[]> exemptUidCaptor = ArgumentCaptor.forClass(int[].class);
-
- inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)),
- exemptUidCaptor.capture());
- assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
-
- if (add) {
- inOrder.verify(mMockNetd, times(1))
- .networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
- eq(toUidRangeStableParcels(vpnRanges)));
- } else {
- inOrder.verify(mMockNetd, times(1))
- .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()),
- eq(toUidRangeStableParcels(vpnRanges)));
- }
-
- inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)),
- exemptUidCaptor.capture());
- assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
- }
-
- @Test
- public void testVpnUidRangesUpdate() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- final UidRange vpnRange = PRIMARY_UIDRANGE;
- Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
- mMockVpn.establish(lp, VPN_UID, vpnRanges);
- assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
-
- reset(mMockNetd);
- // Update to new range which is old range minus APP1, i.e. only APP2
- final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
- new UidRange(vpnRange.start, APP1_UID - 1),
- new UidRange(APP1_UID + 1, vpnRange.stop)));
- mMockVpn.setUids(newRanges);
- waitForIdle();
-
- assertVpnUidRangesUpdated(true, newRanges, VPN_UID);
- assertVpnUidRangesUpdated(false, vpnRanges, VPN_UID);
- }
-
- @Test
- public void testInvalidRequestTypes() {
- final int[] invalidReqTypeInts = new int[]{-1, NetworkRequest.Type.NONE.ordinal(),
- NetworkRequest.Type.LISTEN.ordinal(), NetworkRequest.Type.values().length};
- final NetworkCapabilities nc = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
-
- for (int reqTypeInt : invalidReqTypeInts) {
- assertThrows("Expect throws for invalid request type " + reqTypeInt,
- IllegalArgumentException.class,
- () -> mService.requestNetwork(Process.INVALID_UID, nc, reqTypeInt, null, 0,
- null, ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
- mContext.getPackageName(), getAttributionTag())
- );
- }
- }
-
- @Test
- public void testKeepConnected() throws Exception {
- setAlwaysOnNetworks(false);
- registerDefaultNetworkCallbacks();
- final TestNetworkCallback allNetworksCb = new TestNetworkCallback();
- final NetworkRequest allNetworksRequest = new NetworkRequest.Builder().clearCapabilities()
- .build();
- mCm.registerNetworkCallback(allNetworksRequest, allNetworksCb);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true /* validated */);
-
- mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- allNetworksCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true /* validated */);
-
- mDefaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- // While the default callback doesn't see the network before it's validated, the listen
- // sees the network come up and validate later
- allNetworksCb.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- allNetworksCb.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- allNetworksCb.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- allNetworksCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
- TEST_LINGER_DELAY_MS * 2);
-
- // The cell network has disconnected (see LOST above) because it was outscored and
- // had no requests (see setAlwaysOnNetworks(false) above)
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- final NetworkScore score = new NetworkScore.Builder().setLegacyInt(30).build();
- mCellNetworkAgent.setScore(score);
- mCellNetworkAgent.connect(false /* validated */);
-
- // The cell network gets torn down right away.
- allNetworksCb.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- allNetworksCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
- TEST_NASCENT_DELAY_MS * 2);
- allNetworksCb.assertNoCallback();
-
- // Now create a cell network with KEEP_CONNECTED_FOR_HANDOVER and make sure it's
- // not disconnected immediately when outscored.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- final NetworkScore scoreKeepup = new NetworkScore.Builder().setLegacyInt(30)
- .setKeepConnectedReason(KEEP_CONNECTED_FOR_HANDOVER).build();
- mCellNetworkAgent.setScore(scoreKeepup);
- mCellNetworkAgent.connect(true /* validated */);
-
- allNetworksCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mDefaultNetworkCallback.assertNoCallback();
-
- mWiFiNetworkAgent.disconnect();
-
- allNetworksCb.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
-
- // Reconnect a WiFi network and make sure the cell network is still not torn down.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true /* validated */);
-
- allNetworksCb.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- mDefaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-
- // Now remove the reason to keep connected and make sure the network lingers and is
- // torn down.
- mCellNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(30).build());
- allNetworksCb.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent,
- TEST_NASCENT_DELAY_MS * 2);
- allNetworksCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
- TEST_LINGER_DELAY_MS * 2);
- mDefaultNetworkCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(allNetworksCb);
- // mDefaultNetworkCallback will be unregistered by tearDown()
- }
-
- private class QosCallbackMockHelper {
- @NonNull public final QosFilter mFilter;
- @NonNull public final IQosCallback mCallback;
- @NonNull public final TestNetworkAgentWrapper mAgentWrapper;
- @NonNull private final List<IQosCallback> mCallbacks = new ArrayList();
-
- QosCallbackMockHelper() throws Exception {
- Log.d(TAG, "QosCallbackMockHelper: ");
- mFilter = mock(QosFilter.class);
-
- // Ensure the network is disconnected before anything else occurs
- assertNull(mCellNetworkAgent);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- waitForIdle();
- final Network network = mCellNetworkAgent.getNetwork();
-
- final Pair<IQosCallback, IBinder> pair = createQosCallback();
- mCallback = pair.first;
-
- when(mFilter.getNetwork()).thenReturn(network);
- when(mFilter.validate()).thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
- mAgentWrapper = mCellNetworkAgent;
- }
-
- void registerQosCallback(@NonNull final QosFilter filter,
- @NonNull final IQosCallback callback) {
- mCallbacks.add(callback);
- final NetworkAgentInfo nai =
- mService.getNetworkAgentInfoForNetwork(filter.getNetwork());
- mService.registerQosCallbackInternal(filter, callback, nai);
- }
-
- void tearDown() {
- for (int i = 0; i < mCallbacks.size(); i++) {
- mService.unregisterQosCallback(mCallbacks.get(i));
- }
- }
- }
-
- private Pair<IQosCallback, IBinder> createQosCallback() {
- final IQosCallback callback = mock(IQosCallback.class);
- final IBinder binder = mock(Binder.class);
- when(callback.asBinder()).thenReturn(binder);
- when(binder.isBinderAlive()).thenReturn(true);
- return new Pair<>(callback, binder);
- }
-
-
- @Test
- public void testQosCallbackRegistration() throws Exception {
- mQosCallbackMockHelper = new QosCallbackMockHelper();
- final NetworkAgentWrapper wrapper = mQosCallbackMockHelper.mAgentWrapper;
-
- when(mQosCallbackMockHelper.mFilter.validate())
- .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
- mQosCallbackMockHelper.registerQosCallback(
- mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
-
- final NetworkAgentWrapper.CallbackType.OnQosCallbackRegister cbRegister1 =
- (NetworkAgentWrapper.CallbackType.OnQosCallbackRegister)
- wrapper.getCallbackHistory().poll(1000, x -> true);
- assertNotNull(cbRegister1);
-
- final int registerCallbackId = cbRegister1.mQosCallbackId;
- mService.unregisterQosCallback(mQosCallbackMockHelper.mCallback);
- final NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister cbUnregister;
- cbUnregister = (NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister)
- wrapper.getCallbackHistory().poll(1000, x -> true);
- assertNotNull(cbUnregister);
- assertEquals(registerCallbackId, cbUnregister.mQosCallbackId);
- assertNull(wrapper.getCallbackHistory().poll(200, x -> true));
- }
-
- @Test
- public void testQosCallbackNoRegistrationOnValidationError() throws Exception {
- mQosCallbackMockHelper = new QosCallbackMockHelper();
-
- when(mQosCallbackMockHelper.mFilter.validate())
- .thenReturn(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
- mQosCallbackMockHelper.registerQosCallback(
- mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
- waitForIdle();
- verify(mQosCallbackMockHelper.mCallback)
- .onError(eq(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED));
- }
-
- @Test
- public void testQosCallbackAvailableAndLost() throws Exception {
- mQosCallbackMockHelper = new QosCallbackMockHelper();
- final int sessionId = 10;
- final int qosCallbackId = 1;
-
- when(mQosCallbackMockHelper.mFilter.validate())
- .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
- mQosCallbackMockHelper.registerQosCallback(
- mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
- waitForIdle();
-
- final EpsBearerQosSessionAttributes attributes = new EpsBearerQosSessionAttributes(
- 1, 2, 3, 4, 5, new ArrayList<>());
- mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
- waitForIdle();
-
- verify(mQosCallbackMockHelper.mCallback).onQosEpsBearerSessionAvailable(argThat(session ->
- session.getSessionId() == sessionId
- && session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
-
- mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_EPS_BEARER);
- waitForIdle();
- verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
- session.getSessionId() == sessionId
- && session.getSessionType() == QosSession.TYPE_EPS_BEARER));
- }
-
- @Test
- public void testNrQosCallbackAvailableAndLost() throws Exception {
- mQosCallbackMockHelper = new QosCallbackMockHelper();
- final int sessionId = 10;
- final int qosCallbackId = 1;
-
- when(mQosCallbackMockHelper.mFilter.validate())
- .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
- mQosCallbackMockHelper.registerQosCallback(
- mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
- waitForIdle();
-
- final NrQosSessionAttributes attributes = new NrQosSessionAttributes(
- 1, 2, 3, 4, 5, 6, 7, new ArrayList<>());
- mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
- waitForIdle();
-
- verify(mQosCallbackMockHelper.mCallback).onNrQosSessionAvailable(argThat(session ->
- session.getSessionId() == sessionId
- && session.getSessionType() == QosSession.TYPE_NR_BEARER), eq(attributes));
-
- mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_NR_BEARER);
- waitForIdle();
- verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
- session.getSessionId() == sessionId
- && session.getSessionType() == QosSession.TYPE_NR_BEARER));
- }
-
- @Test
- public void testQosCallbackTooManyRequests() throws Exception {
- mQosCallbackMockHelper = new QosCallbackMockHelper();
-
- when(mQosCallbackMockHelper.mFilter.validate())
- .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
- for (int i = 0; i < 100; i++) {
- final Pair<IQosCallback, IBinder> pair = createQosCallback();
-
- try {
- mQosCallbackMockHelper.registerQosCallback(
- mQosCallbackMockHelper.mFilter, pair.first);
- } catch (ServiceSpecificException e) {
- assertEquals(e.errorCode, ConnectivityManager.Errors.TOO_MANY_REQUESTS);
- if (i < 50) {
- fail("TOO_MANY_REQUESTS thrown too early, the count is " + i);
- }
-
- // As long as there is at least 50 requests, it is safe to assume it works.
- // Note: The count isn't being tested precisely against 100 because the counter
- // is shared with request network.
- return;
- }
- }
- fail("TOO_MANY_REQUESTS never thrown");
- }
-
- private UidRange createUidRange(int userId) {
- return UidRange.createForUser(UserHandle.of(userId));
- }
-
- private void mockGetApplicationInfo(@NonNull final String packageName, @NonNull final int uid) {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.uid = uid;
- try {
- when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
- .thenReturn(applicationInfo);
- } catch (Exception e) {
- fail(e.getMessage());
- }
- }
-
- private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName)
- throws Exception {
- when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
- .thenThrow(new PackageManager.NameNotFoundException(packageName));
- }
-
- private void mockHasSystemFeature(@NonNull final String featureName,
- @NonNull final boolean hasFeature) {
- when(mPackageManager.hasSystemFeature(eq(featureName)))
- .thenReturn(hasFeature);
- }
-
- private Range<Integer> getNriFirstUidRange(
- @NonNull final ConnectivityService.NetworkRequestInfo nri) {
- return nri.mRequests.get(0).networkCapabilities.getUids().iterator().next();
- }
-
- private OemNetworkPreferences createDefaultOemNetworkPreferences(
- @OemNetworkPreferences.OemNetworkPreference final int preference) {
- // Arrange PackageManager mocks
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
-
- // Build OemNetworkPreferences object
- return new OemNetworkPreferences.Builder()
- .addNetworkPreference(TEST_PACKAGE_NAME, preference)
- .build();
- }
-
- @Test
- public void testOemNetworkRequestFactoryPreferenceUninitializedThrowsError()
- throws PackageManager.NameNotFoundException {
- @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
- OEM_NETWORK_PREFERENCE_UNINITIALIZED;
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- assertThrows(IllegalArgumentException.class,
- () -> mService.new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(
- createDefaultOemNetworkPreferences(prefToTest)));
- }
-
- @Test
- public void testOemNetworkRequestFactoryPreferenceOemPaid()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 1;
- final int expectedNumOfRequests = 3;
-
- @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(
- createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
- assertEquals(expectedNumOfNris, nris.size());
- assertEquals(expectedNumOfRequests, mRequests.size());
- assertTrue(mRequests.get(0).isListen());
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_VALIDATED));
- assertTrue(mRequests.get(1).isRequest());
- assertTrue(mRequests.get(1).hasCapability(NET_CAPABILITY_OEM_PAID));
- assertEquals(NetworkRequest.Type.TRACK_DEFAULT, mRequests.get(2).type);
- assertTrue(mService.getDefaultRequest().networkCapabilities.equalsNetCapabilities(
- mRequests.get(2).networkCapabilities));
- }
-
- @Test
- public void testOemNetworkRequestFactoryPreferenceOemPaidNoFallback()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 1;
- final int expectedNumOfRequests = 2;
-
- @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
- OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(
- createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
- assertEquals(expectedNumOfNris, nris.size());
- assertEquals(expectedNumOfRequests, mRequests.size());
- assertTrue(mRequests.get(0).isListen());
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_VALIDATED));
- assertTrue(mRequests.get(1).isRequest());
- assertTrue(mRequests.get(1).hasCapability(NET_CAPABILITY_OEM_PAID));
- }
-
- @Test
- public void testOemNetworkRequestFactoryPreferenceOemPaidOnly()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 1;
- final int expectedNumOfRequests = 1;
-
- @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(
- createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
- assertEquals(expectedNumOfNris, nris.size());
- assertEquals(expectedNumOfRequests, mRequests.size());
- assertTrue(mRequests.get(0).isRequest());
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_OEM_PAID));
- }
-
- @Test
- public void testOemNetworkRequestFactoryPreferenceOemPrivateOnly()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 1;
- final int expectedNumOfRequests = 1;
-
- @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
- OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(
- createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
- assertEquals(expectedNumOfNris, nris.size());
- assertEquals(expectedNumOfRequests, mRequests.size());
- assertTrue(mRequests.get(0).isRequest());
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_OEM_PRIVATE));
- assertFalse(mRequests.get(0).hasCapability(NET_CAPABILITY_OEM_PAID));
- }
-
- @Test
- public void testOemNetworkRequestFactoryCreatesCorrectNumOfNris()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 2;
-
- // Arrange PackageManager mocks
- final String testPackageName2 = "com.google.apps.dialer";
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
- mockGetApplicationInfo(testPackageName2, TEST_PACKAGE_UID);
-
- // Build OemNetworkPreferences object
- final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
- final int testOemPref2 = OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
- .addNetworkPreference(testPackageName2, testOemPref2)
- .build();
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(pref);
-
- assertNotNull(nris);
- assertEquals(expectedNumOfNris, nris.size());
- }
-
- @Test
- public void testOemNetworkRequestFactoryMultiplePrefsCorrectlySetsUids()
- throws Exception {
- // Arrange PackageManager mocks
- final String testPackageName2 = "com.google.apps.dialer";
- final int testPackageNameUid2 = 456;
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
- mockGetApplicationInfo(testPackageName2, testPackageNameUid2);
-
- // Build OemNetworkPreferences object
- final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
- final int testOemPref2 = OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
- .addNetworkPreference(testPackageName2, testOemPref2)
- .build();
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final List<ConnectivityService.NetworkRequestInfo> nris =
- new ArrayList<>(
- mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
- pref));
-
- // Sort by uid to access nris by index
- nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).getLower()));
- assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getLower());
- assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getUpper());
- assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getLower());
- assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getUpper());
- }
-
- @Test
- public void testOemNetworkRequestFactoryMultipleUsersCorrectlySetsUids()
- throws Exception {
- // Arrange users
- final int secondUser = 10;
- final UserHandle secondUserHandle = new UserHandle(secondUser);
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
-
- // Arrange PackageManager mocks
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
-
- // Build OemNetworkPreferences object
- final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
- .build();
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final List<ConnectivityService.NetworkRequestInfo> nris =
- new ArrayList<>(
- mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
- pref));
-
- // UIDs for all users and all managed packages should be present.
- // Two users each with two packages.
- final int expectedUidSize = 2;
- final List<Range<Integer>> uids =
- new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids());
- assertEquals(expectedUidSize, uids.size());
-
- // Sort by uid to access nris by index
- uids.sort(Comparator.comparingInt(uid -> uid.getLower()));
- final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
- assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getLower());
- assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getUpper());
- assertEquals(secondUserTestPackageUid, (int) uids.get(1).getLower());
- assertEquals(secondUserTestPackageUid, (int) uids.get(1).getUpper());
- }
-
- @Test
- public void testOemNetworkRequestFactoryAddsPackagesToCorrectPreference()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 1;
- final int expectedNumOfAppUids = 2;
-
- // Arrange PackageManager mocks
- final String testPackageName2 = "com.google.apps.dialer";
- final int testPackageNameUid2 = 456;
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
- mockGetApplicationInfo(testPackageName2, testPackageNameUid2);
-
- // Build OemNetworkPreferences object
- final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
- .addNetworkPreference(testPackageName2, testOemPref)
- .build();
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(pref);
-
- assertEquals(expectedNumOfNris, nris.size());
- assertEquals(expectedNumOfAppUids,
- nris.iterator().next().mRequests.get(0).networkCapabilities.getUids().size());
- }
-
- @Test
- public void testSetOemNetworkPreferenceNullListenerAndPrefParamThrowsNpe() {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
-
- // Act on ConnectivityService.setOemNetworkPreference()
- assertThrows(NullPointerException.class,
- () -> mService.setOemNetworkPreference(
- null,
- null));
- }
-
- @Test
- public void testSetOemNetworkPreferenceFailsForNonAutomotive()
- throws Exception {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, false);
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
-
- // Act on ConnectivityService.setOemNetworkPreference()
- assertThrows(UnsupportedOperationException.class,
- () -> mService.setOemNetworkPreference(
- createDefaultOemNetworkPreferences(networkPref),
- new TestOemListenerCallback()));
- }
-
- private void setOemNetworkPreferenceAgentConnected(final int transportType,
- final boolean connectAgent) throws Exception {
- switch(transportType) {
- // Corresponds to a metered cellular network. Will be used for the default network.
- case TRANSPORT_CELLULAR:
- if (!connectAgent) {
- mCellNetworkAgent.disconnect();
- break;
- }
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- break;
- // Corresponds to a restricted ethernet network with OEM_PAID/OEM_PRIVATE.
- case TRANSPORT_ETHERNET:
- if (!connectAgent) {
- stopOemManagedNetwork();
- break;
- }
- startOemManagedNetwork(true);
- break;
- // Corresponds to unmetered Wi-Fi.
- case TRANSPORT_WIFI:
- if (!connectAgent) {
- mWiFiNetworkAgent.disconnect();
- break;
- }
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- break;
- default:
- throw new AssertionError("Unsupported transport type passed in.");
-
- }
- waitForIdle();
- }
-
- private void startOemManagedNetwork(final boolean isOemPaid) throws Exception {
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.addCapability(
- isOemPaid ? NET_CAPABILITY_OEM_PAID : NET_CAPABILITY_OEM_PRIVATE);
- mEthernetNetworkAgent.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- mEthernetNetworkAgent.connect(true);
- }
-
- private void stopOemManagedNetwork() {
- mEthernetNetworkAgent.disconnect();
- waitForIdle();
- }
-
- private void verifyMultipleDefaultNetworksTracksCorrectly(
- final int expectedOemRequestsSize,
- @NonNull final Network expectedDefaultNetwork,
- @NonNull final Network expectedPerAppNetwork) {
- // The current test setup assumes two tracked default network requests; one for the default
- // network and the other for the OEM network preference being tested. This will be validated
- // each time to confirm it doesn't change under test.
- final int expectedDefaultNetworkRequestsSize = 2;
- assertEquals(expectedDefaultNetworkRequestsSize, mService.mDefaultNetworkRequests.size());
- for (final ConnectivityService.NetworkRequestInfo defaultRequest
- : mService.mDefaultNetworkRequests) {
- final Network defaultNetwork = defaultRequest.getSatisfier() == null
- ? null : defaultRequest.getSatisfier().network();
- // If this is the default request.
- if (defaultRequest == mService.mDefaultRequest) {
- assertEquals(
- expectedDefaultNetwork,
- defaultNetwork);
- // Make sure this value doesn't change.
- assertEquals(1, defaultRequest.mRequests.size());
- continue;
- }
- assertEquals(expectedPerAppNetwork, defaultNetwork);
- assertEquals(expectedOemRequestsSize, defaultRequest.mRequests.size());
- }
- verifyMultipleDefaultCallbacks(expectedDefaultNetwork, expectedPerAppNetwork);
- }
-
- /**
- * Verify default callbacks for 'available' fire as expected. This will only run if
- * registerDefaultNetworkCallbacks() was executed prior and will only be different if the
- * setOemNetworkPreference() per-app API was used for the current process.
- * @param expectedSystemDefault the expected network for the system default.
- * @param expectedPerAppDefault the expected network for the current process's default.
- */
- private void verifyMultipleDefaultCallbacks(
- @NonNull final Network expectedSystemDefault,
- @NonNull final Network expectedPerAppDefault) {
- if (null != mSystemDefaultNetworkCallback && null != expectedSystemDefault
- && mService.mNoServiceNetwork.network() != expectedSystemDefault) {
- // getLastAvailableNetwork() is used as this method can be called successively with
- // the same network to validate therefore expectAvailableThenValidatedCallbacks
- // can't be used.
- assertEquals(mSystemDefaultNetworkCallback.getLastAvailableNetwork(),
- expectedSystemDefault);
- }
- if (null != mDefaultNetworkCallback && null != expectedPerAppDefault
- && mService.mNoServiceNetwork.network() != expectedPerAppDefault) {
- assertEquals(mDefaultNetworkCallback.getLastAvailableNetwork(),
- expectedPerAppDefault);
- }
- }
-
- private void registerDefaultNetworkCallbacks() {
- // Using Manifest.permission.NETWORK_SETTINGS for registerSystemDefaultNetworkCallback()
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
- mSystemDefaultNetworkCallback = new TestNetworkCallback();
- mDefaultNetworkCallback = new TestNetworkCallback();
- mProfileDefaultNetworkCallback = new TestNetworkCallback();
- mCm.registerSystemDefaultNetworkCallback(mSystemDefaultNetworkCallback,
- new Handler(ConnectivityThread.getInstanceLooper()));
- mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback);
- registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback,
- TEST_WORK_PROFILE_APP_UID);
- // TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
- }
-
- private void unregisterDefaultNetworkCallbacks() {
- if (null != mDefaultNetworkCallback) {
- mCm.unregisterNetworkCallback(mDefaultNetworkCallback);
- }
- if (null != mSystemDefaultNetworkCallback) {
- mCm.unregisterNetworkCallback(mSystemDefaultNetworkCallback);
- }
- if (null != mProfileDefaultNetworkCallback) {
- mCm.unregisterNetworkCallback(mProfileDefaultNetworkCallback);
- }
- }
-
- private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
- @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup)
- throws Exception {
- final int testPackageNameUid = TEST_PACKAGE_UID;
- final String testPackageName = "per.app.defaults.package";
- setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
- networkPrefToSetup, testPackageNameUid, testPackageName);
- }
-
- private void setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(
- @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup)
- throws Exception {
- final int testPackageNameUid = Process.myUid();
- final String testPackageName = "per.app.defaults.package";
- setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
- networkPrefToSetup, testPackageNameUid, testPackageName);
- }
-
- private void setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
- @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
- final int testPackageUid, @NonNull final String testPackageName) throws Exception {
- // Only the default request should be included at start.
- assertEquals(1, mService.mDefaultNetworkRequests.size());
-
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(testPackageUid));
- setupSetOemNetworkPreferenceForPreferenceTest(
- networkPrefToSetup, uidRanges, testPackageName);
- }
-
- private void setupSetOemNetworkPreferenceForPreferenceTest(
- @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
- @NonNull final UidRangeParcel[] uidRanges,
- @NonNull final String testPackageName)
- throws Exception {
- // These tests work off a single UID therefore using 'start' is valid.
- mockGetApplicationInfo(testPackageName, uidRanges[0].start);
-
- setOemNetworkPreference(networkPrefToSetup, testPackageName);
- }
-
- private void setOemNetworkPreference(final int networkPrefToSetup,
- @NonNull final String... testPackageNames)
- throws Exception {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
-
- // Build OemNetworkPreferences object
- final OemNetworkPreferences.Builder builder = new OemNetworkPreferences.Builder();
- for (final String packageName : testPackageNames) {
- builder.addNetworkPreference(packageName, networkPrefToSetup);
- }
- final OemNetworkPreferences pref = builder.build();
-
- // Act on ConnectivityService.setOemNetworkPreference()
- final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
- mService.setOemNetworkPreference(pref, oemPrefListener);
-
- // Verify call returned successfully
- oemPrefListener.expectOnComplete();
- }
-
- private static class TestOemListenerCallback implements IOnCompleteListener {
- final CompletableFuture<Object> mDone = new CompletableFuture<>();
-
- @Override
- public void onComplete() {
- mDone.complete(new Object());
- }
-
- void expectOnComplete() {
- try {
- mDone.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- fail("Expected onComplete() not received after " + TIMEOUT_MS + " ms");
- } catch (Exception e) {
- fail(e.getMessage());
- }
- }
-
- @Override
- public IBinder asBinder() {
- return null;
- }
- }
-
- @Test
- public void testMultiDefaultGetActiveNetworkIsCorrect() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- final int expectedOemPrefRequestSize = 1;
- registerDefaultNetworkCallbacks();
-
- // Setup the test process to use networkPref for their default network.
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- // The active network for the default should be null at this point as this is a retricted
- // network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // Verify that the active network is correct
- verifyActiveNetwork(TRANSPORT_ETHERNET);
- // default NCs will be unregistered in tearDown
- }
-
- @Test
- public void testMultiDefaultIsActiveNetworkMeteredIsCorrect() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- final int expectedOemPrefRequestSize = 1;
- registerDefaultNetworkCallbacks();
-
- // Setup the test process to use networkPref for their default network.
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
-
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // Connect to an unmetered restricted network that will only be available to the OEM pref.
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.addCapability(NET_CAPABILITY_OEM_PAID);
- mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mEthernetNetworkAgent.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- mEthernetNetworkAgent.connect(true);
- waitForIdle();
-
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- assertFalse(mCm.isActiveNetworkMetered());
- // default NCs will be unregistered in tearDown
- }
-
- @Test
- public void testPerAppDefaultRegisterDefaultNetworkCallback() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- final int expectedOemPrefRequestSize = 1;
- final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
-
- // Register the default network callback before the pref is already set. This means that
- // the policy will be applied to the callback on setOemNetworkPreference().
- mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
- defaultNetworkCallback.assertNoCallback();
-
- final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
- withPermission(NETWORK_SETTINGS, () ->
- mCm.registerDefaultNetworkCallbackForUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
- new Handler(ConnectivityThread.getInstanceLooper())));
-
- // Setup the test process to use networkPref for their default network.
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- // The active nai for the default is null at this point as this is a restricted network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // At this point with a restricted network used, the available callback should trigger.
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
- mEthernetNetworkAgent.getNetwork());
- otherUidDefaultCallback.assertNoCallback();
-
- // Now bring down the default network which should trigger a LOST callback.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
-
- // At this point, with no network is available, the lost callback should trigger
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- otherUidDefaultCallback.assertNoCallback();
-
- // Confirm we can unregister without issues.
- mCm.unregisterNetworkCallback(defaultNetworkCallback);
- mCm.unregisterNetworkCallback(otherUidDefaultCallback);
- }
-
- @Test
- public void testPerAppDefaultRegisterDefaultNetworkCallbackAfterPrefSet() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- final int expectedOemPrefRequestSize = 1;
- final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
-
- // Setup the test process to use networkPref for their default network.
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
-
- // Register the default network callback after the pref is already set. This means that
- // the policy will be applied to the callback on requestNetwork().
- mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
- defaultNetworkCallback.assertNoCallback();
-
- final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
- withPermission(NETWORK_SETTINGS, () ->
- mCm.registerDefaultNetworkCallbackForUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
- new Handler(ConnectivityThread.getInstanceLooper())));
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- // The active nai for the default is null at this point as this is a restricted network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // At this point with a restricted network used, the available callback should trigger
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
- mEthernetNetworkAgent.getNetwork());
- otherUidDefaultCallback.assertNoCallback();
-
- // Now bring down the default network which should trigger a LOST callback.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- otherUidDefaultCallback.assertNoCallback();
-
- // At this point, with no network is available, the lost callback should trigger
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- otherUidDefaultCallback.assertNoCallback();
-
- // Confirm we can unregister without issues.
- mCm.unregisterNetworkCallback(defaultNetworkCallback);
- mCm.unregisterNetworkCallback(otherUidDefaultCallback);
- }
-
- @Test
- public void testPerAppDefaultRegisterDefaultNetworkCallbackDoesNotFire() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- final int expectedOemPrefRequestSize = 1;
- final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
- final int userId = UserHandle.getUserId(Process.myUid());
-
- mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
- defaultNetworkCallback.assertNoCallback();
-
- final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
- withPermission(NETWORK_SETTINGS, () ->
- mCm.registerDefaultNetworkCallbackForUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
- new Handler(ConnectivityThread.getInstanceLooper())));
-
- // Setup a process different than the test process to use the default network. This means
- // that the defaultNetworkCallback won't be tracked by the per-app policy.
- setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(networkPref);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- // The active nai for the default is null at this point as this is a restricted network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // As this callback does not have access to the OEM_PAID network, it will not fire.
- defaultNetworkCallback.assertNoCallback();
- assertDefaultNetworkCapabilities(userId /* no networks */);
-
- // The other UID does have access, and gets a callback.
- otherUidDefaultCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
-
- // Bring up unrestricted cellular. This should now satisfy the default network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // At this point with an unrestricted network used, the available callback should trigger
- // The other UID is unaffected and remains on the paid network.
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
- mCellNetworkAgent.getNetwork());
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent);
- otherUidDefaultCallback.assertNoCallback();
-
- // Now bring down the per-app network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
-
- // Since the callback didn't use the per-app network, only the other UID gets a callback.
- // Because the preference specifies no fallback, it does not switch to cellular.
- defaultNetworkCallback.assertNoCallback();
- otherUidDefaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
-
- // Now bring down the default network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
-
- // As this callback was tracking the default, this should now trigger.
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- otherUidDefaultCallback.assertNoCallback();
-
- // Confirm we can unregister without issues.
- mCm.unregisterNetworkCallback(defaultNetworkCallback);
- mCm.unregisterNetworkCallback(otherUidDefaultCallback);
- }
-
- /**
- * This method assumes that the same uidRanges input will be used to verify that dependencies
- * are called as expected.
- */
- private void verifySetOemNetworkPreferenceForPreference(
- @NonNull final UidRangeParcel[] uidRanges,
- final int addUidRangesNetId,
- final int addUidRangesTimes,
- final int removeUidRangesNetId,
- final int removeUidRangesTimes,
- final boolean shouldDestroyNetwork) throws RemoteException {
- verifySetOemNetworkPreferenceForPreference(uidRanges, uidRanges,
- addUidRangesNetId, addUidRangesTimes, removeUidRangesNetId, removeUidRangesTimes,
- shouldDestroyNetwork);
- }
-
- private void verifySetOemNetworkPreferenceForPreference(
- @NonNull final UidRangeParcel[] addedUidRanges,
- @NonNull final UidRangeParcel[] removedUidRanges,
- final int addUidRangesNetId,
- final int addUidRangesTimes,
- final int removeUidRangesNetId,
- final int removeUidRangesTimes,
- final boolean shouldDestroyNetwork) throws RemoteException {
- final boolean useAnyIdForAdd = OEM_PREF_ANY_NET_ID == addUidRangesNetId;
- final boolean useAnyIdForRemove = OEM_PREF_ANY_NET_ID == removeUidRangesNetId;
-
- // Validate netd.
- verify(mMockNetd, times(addUidRangesTimes))
- .networkAddUidRanges(
- (useAnyIdForAdd ? anyInt() : eq(addUidRangesNetId)), eq(addedUidRanges));
- verify(mMockNetd, times(removeUidRangesTimes))
- .networkRemoveUidRanges(
- (useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)),
- eq(removedUidRanges));
- if (shouldDestroyNetwork) {
- verify(mMockNetd, times(1))
- .networkDestroy((useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)));
- }
- reset(mMockNetd);
- }
-
- /**
- * Test the tracked default requests clear previous OEM requests on setOemNetworkPreference().
- */
- @Test
- public void testSetOemNetworkPreferenceClearPreviousOemValues() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
- final int testPackageUid = 123;
- final String testPackageName = "com.google.apps.contacts";
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(testPackageUid));
-
- // Validate the starting requests only includes the fallback request.
- assertEquals(1, mService.mDefaultNetworkRequests.size());
-
- // Add an OEM default network request to track.
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, testPackageName);
-
- // Two requests should exist, one for the fallback and one for the pref.
- assertEquals(2, mService.mDefaultNetworkRequests.size());
-
- networkPref = OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, testPackageName);
-
- // Two requests should still exist validating the previous per-app request was replaced.
- assertEquals(2, mService.mDefaultNetworkRequests.size());
- }
-
- /**
- * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
- * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
- */
- @Test
- public void testMultilayerForPreferenceOemPaidEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
-
- // Arrange PackageManager mocks
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
-
- // Verify the starting state. No networks should be connected.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mWiFiNetworkAgent.getNetwork().netId, 1 /* times */,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Disconnecting OEM_PAID should have no effect as it is lower in priority then unmetered.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- // netd should not be called as default networks haven't changed.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Disconnecting unmetered should put PANS on lowest priority fallback request.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mWiFiNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
-
- // Disconnecting the fallback network should result in no connectivity.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- mCellNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order:
- * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
- */
- @Test
- public void testMultilayerForPreferenceOemPaidNoFallbackEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
-
- // Arrange PackageManager mocks
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
-
- // Verify the starting state. This preference doesn't support using the fallback network
- // therefore should be on the disconnected network as it has no networks to connect to.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network.
- // This preference should not use this network as it doesn't support fallback usage.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mWiFiNetworkAgent.getNetwork().netId, 1 /* times */,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Disconnecting unmetered should put PANS on OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- mWiFiNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
-
- // Disconnecting OEM_PAID should result in no connectivity.
- // OEM_PAID_NO_FALLBACK not supporting a fallback now uses the disconnected network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- mEthernetNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY in the following order:
- * NET_CAPABILITY_OEM_PAID
- * This preference should only apply to OEM_PAID networks.
- */
- @Test
- public void testMultilayerForPreferenceOemPaidOnlyEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
-
- // Arrange PackageManager mocks
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
-
- // Verify the starting state. This preference doesn't support using the fallback network
- // therefore should be on the disconnected network as it has no networks to connect to.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up metered cellular. This should not apply to this preference.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up unmetered Wi-Fi. This should not apply to this preference.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Disconnecting OEM_PAID should result in no connectivity.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- mEthernetNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY in the following order:
- * NET_CAPABILITY_OEM_PRIVATE
- * This preference should only apply to OEM_PRIVATE networks.
- */
- @Test
- public void testMultilayerForPreferenceOemPrivateOnlyEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
-
- // Arrange PackageManager mocks
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
-
- // Verify the starting state. This preference doesn't support using the fallback network
- // therefore should be on the disconnected network as it has no networks to connect to.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up metered cellular. This should not apply to this preference.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up unmetered Wi-Fi. This should not apply to this preference.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up ethernet with OEM_PRIVATE. This will satisfy NET_CAPABILITY_OEM_PRIVATE.
- startOemManagedNetwork(false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Disconnecting OEM_PRIVATE should result in no connectivity.
- stopOemManagedNetwork();
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- mEthernetNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
- }
-
- @Test
- public void testMultilayerForMultipleUsersEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
-
- // Arrange users
- final int secondUser = 10;
- final UserHandle secondUserHandle = new UserHandle(secondUser);
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
-
- // Arrange PackageManager mocks
- final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(
- uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
-
- // Verify the starting state. No networks should be connected.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test that we correctly add the expected values for multiple users.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test that we correctly remove the expected values for multiple users.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- mCellNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
- }
-
- @Test
- public void testMultilayerForBroadcastedUsersEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
-
- // Arrange users
- final int secondUser = 10;
- final UserHandle secondUserHandle = new UserHandle(secondUser);
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE));
-
- // Arrange PackageManager mocks
- final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
- final UidRangeParcel[] uidRangesSingleUser =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- final UidRangeParcel[] uidRangesBothUsers =
- toUidRangeStableParcels(
- uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
- setupSetOemNetworkPreferenceForPreferenceTest(
- networkPref, uidRangesSingleUser, TEST_PACKAGE_NAME);
-
- // Verify the starting state. No networks should be connected.
- verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test that we correctly add the expected values for multiple users.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Send a broadcast indicating a user was added.
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
- final Intent addedIntent = new Intent(ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(secondUser));
- processBroadcast(addedIntent);
-
- // Test that we correctly add values for all users and remove for the single user.
- verifySetOemNetworkPreferenceForPreference(uidRangesBothUsers, uidRangesSingleUser,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Send a broadcast indicating a user was removed.
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE));
- final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
- removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(secondUser));
- processBroadcast(removedIntent);
-
- // Test that we correctly add values for the single user and remove for the all users.
- verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser, uidRangesBothUsers,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
- }
-
- @Test
- public void testMultilayerForPackageChangesEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
- final String packageScheme = "package:";
-
- // Arrange PackageManager mocks
- final String packageToInstall = "package.to.install";
- final int packageToInstallUid = 81387;
- final UidRangeParcel[] uidRangesSinglePackage =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
- mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
- setOemNetworkPreference(networkPref, TEST_PACKAGE_NAME, packageToInstall);
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid(), packageToInstall);
-
- // Verify the starting state. No networks should be connected.
- verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test that we correctly add the expected values for installed packages.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Set the system to recognize the package to be installed
- mockGetApplicationInfo(packageToInstall, packageToInstallUid);
- final UidRangeParcel[] uidRangesAllPackages =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID, packageToInstallUid));
-
- // Send a broadcast indicating a package was installed.
- final Intent addedIntent = new Intent(ACTION_PACKAGE_ADDED);
- addedIntent.setData(Uri.parse(packageScheme + packageToInstall));
- processBroadcast(addedIntent);
-
- // Test the single package is removed and the combined packages are added.
- verifySetOemNetworkPreferenceForPreference(uidRangesAllPackages, uidRangesSinglePackage,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Set the system to no longer recognize the package to be installed
- mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
-
- // Send a broadcast indicating a package was removed.
- final Intent removedIntent = new Intent(ACTION_PACKAGE_REMOVED);
- removedIntent.setData(Uri.parse(packageScheme + packageToInstall));
- processBroadcast(removedIntent);
-
- // Test the combined packages are removed and the single package is added.
- verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage, uidRangesAllPackages,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Set the system to change the installed package's uid
- final int replacedTestPackageUid = TEST_PACKAGE_UID + 1;
- mockGetApplicationInfo(TEST_PACKAGE_NAME, replacedTestPackageUid);
- final UidRangeParcel[] uidRangesReplacedPackage =
- toUidRangeStableParcels(uidRangesForUids(replacedTestPackageUid));
-
- // Send a broadcast indicating a package was replaced.
- final Intent replacedIntent = new Intent(ACTION_PACKAGE_REPLACED);
- replacedIntent.setData(Uri.parse(packageScheme + TEST_PACKAGE_NAME));
- processBroadcast(replacedIntent);
-
- // Test the original uid is removed and is replaced with the new uid.
- verifySetOemNetworkPreferenceForPreference(uidRangesReplacedPackage, uidRangesSinglePackage,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
- }
-
- /**
- * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
- * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
- */
- @Test
- public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
- final int expectedDefaultRequestSize = 2;
- final int expectedOemPrefRequestSize = 3;
- registerDefaultNetworkCallbacks();
-
- // The fallback as well as the OEM preference should now be tracked.
- assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mCellNetworkAgent.getNetwork());
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mWiFiNetworkAgent.getNetwork(),
- mWiFiNetworkAgent.getNetwork());
-
- // Disconnecting unmetered Wi-Fi will put the pref on OEM_PAID and fallback on cellular.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting OEM_PAID will put both on null as it is the last network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- null);
-
- // default callbacks will be unregistered in tearDown
- }
-
- @Test
- public void testNetworkFactoryRequestsWithMultilayerRequest()
- throws Exception {
- // First use OEM_PAID preference to create a multi-layer request : 1. listen for
- // unmetered, 2. request network with cap OEM_PAID, 3, request the default network for
- // fallback.
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
-
- final HandlerThread handlerThread = new HandlerThread("MockFactory");
- handlerThread.start();
- NetworkCapabilities internetFilter = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- final MockNetworkFactory internetFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "internetFactory", internetFilter, mCsHandlerThread);
- internetFactory.setScoreFilter(40);
- internetFactory.register();
- // Default internet request only. The unmetered request is never sent to factories (it's a
- // LISTEN, not requestable). The 3rd (fallback) request in OEM_PAID NRI is TRACK_DEFAULT
- // which is also not sent to factories. Finally, the OEM_PAID request doesn't match the
- // internetFactory filter.
- internetFactory.expectRequestAdds(1);
- internetFactory.assertRequestCountEquals(1);
-
- NetworkCapabilities oemPaidFilter = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_OEM_PAID)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- final MockNetworkFactory oemPaidFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "oemPaidFactory", oemPaidFilter, mCsHandlerThread);
- oemPaidFactory.setScoreFilter(40);
- oemPaidFactory.register();
- oemPaidFactory.expectRequestAdd(); // Because nobody satisfies the request
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- // A network connected that satisfies the default internet request. For the OEM_PAID
- // preference, this is not as good as an OEM_PAID network, so even if the score of
- // the network is better than the factory announced, it still should try to bring up
- // the network.
- expectNoRequestChanged(oemPaidFactory);
- oemPaidFactory.assertRequestCountEquals(1);
- // The internet factory however is outscored, and should lose its requests.
- internetFactory.expectRequestRemove();
- internetFactory.assertRequestCountEquals(0);
-
- final NetworkCapabilities oemPaidNc = new NetworkCapabilities();
- oemPaidNc.addCapability(NET_CAPABILITY_OEM_PAID);
- oemPaidNc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- final TestNetworkAgentWrapper oemPaidAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR,
- new LinkProperties(), oemPaidNc);
- oemPaidAgent.connect(true);
-
- // The oemPaidAgent has score 50/cell transport, so it beats what the oemPaidFactory can
- // provide, therefore it loses the request.
- oemPaidFactory.expectRequestRemove();
- oemPaidFactory.assertRequestCountEquals(0);
- expectNoRequestChanged(internetFactory);
- internetFactory.assertRequestCountEquals(0);
-
- oemPaidAgent.setScore(new NetworkScore.Builder().setLegacyInt(20).setExiting(true).build());
- // Now the that the agent is weak, the oemPaidFactory can beat the existing network for the
- // OEM_PAID request. The internet factory however can't beat a network that has OEM_PAID
- // for the preference request, so it doesn't see the request.
- oemPaidFactory.expectRequestAdd();
- oemPaidFactory.assertRequestCountEquals(1);
- expectNoRequestChanged(internetFactory);
- internetFactory.assertRequestCountEquals(0);
-
- mCellNetworkAgent.disconnect();
- // The network satisfying the default internet request has disconnected, so the
- // internetFactory sees the default request again. However there is a network with OEM_PAID
- // connected, so the 2nd OEM_PAID req is already satisfied, so the oemPaidFactory doesn't
- // care about networks that don't have OEM_PAID.
- expectNoRequestChanged(oemPaidFactory);
- oemPaidFactory.assertRequestCountEquals(1);
- internetFactory.expectRequestAdd();
- internetFactory.assertRequestCountEquals(1);
-
- // Cell connects again, still with score 50. Back to the previous state.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- expectNoRequestChanged(oemPaidFactory);
- oemPaidFactory.assertRequestCountEquals(1);
- internetFactory.expectRequestRemove();
- internetFactory.assertRequestCountEquals(0);
-
- // Create a request that holds the upcoming wifi network.
- final TestNetworkCallback wifiCallback = new TestNetworkCallback();
- mCm.requestNetwork(new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build(),
- wifiCallback);
-
- // Now WiFi connects and it's unmetered, but it's weaker than cell.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(30).setExiting(true)
- .build()); // Not the best Internet network, but unmetered
- mWiFiNetworkAgent.connect(true);
-
- // The OEM_PAID preference prefers an unmetered network to an OEM_PAID network, so
- // the oemPaidFactory can't beat wifi no matter how high its score.
- oemPaidFactory.expectRequestRemove();
- expectNoRequestChanged(internetFactory);
-
- mCellNetworkAgent.disconnect();
- // Now that the best internet network (cell, with its 50 score compared to 30 for WiFi
- // at this point), the default internet request is satisfied by a network worse than
- // the internetFactory announced, so it gets the request. However, there is still an
- // unmetered network, so the oemPaidNetworkFactory still can't beat this.
- expectNoRequestChanged(oemPaidFactory);
- internetFactory.expectRequestAdd();
- mCm.unregisterNetworkCallback(wifiCallback);
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order:
- * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
- */
- @Test
- public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidNoFallbackCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
- final int expectedDefaultRequestSize = 2;
- final int expectedOemPrefRequestSize = 2;
- registerDefaultNetworkCallbacks();
-
- // The fallback as well as the OEM preference should now be tracked.
- assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network but not the pref.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mService.mNoServiceNetwork.network());
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mWiFiNetworkAgent.getNetwork(),
- mWiFiNetworkAgent.getNetwork());
-
- // Disconnecting unmetered Wi-Fi will put the OEM pref on OEM_PAID and fallback on cellular.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting OEM_PAID puts the fallback on null and the pref on the disconnected net.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mService.mNoServiceNetwork.network());
-
- // default callbacks will be unregistered in tearDown
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY in the following order:
- * NET_CAPABILITY_OEM_PAID
- * This preference should only apply to OEM_PAID networks.
- */
- @Test
- public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidOnlyCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
- final int expectedDefaultRequestSize = 2;
- final int expectedOemPrefRequestSize = 1;
- registerDefaultNetworkCallbacks();
-
- // The fallback as well as the OEM preference should now be tracked.
- assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mService.mNoServiceNetwork.network());
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mWiFiNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting OEM_PAID will keep the fallback on cellular and nothing for OEM_PAID.
- // OEM_PAID_ONLY not supporting a fallback now uses the disconnected network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mService.mNoServiceNetwork.network());
-
- // Disconnecting cellular will put the fallback on null and the pref on disconnected.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mService.mNoServiceNetwork.network());
-
- // default callbacks will be unregistered in tearDown
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY in the following order:
- * NET_CAPABILITY_OEM_PRIVATE
- * This preference should only apply to OEM_PRIVATE networks.
- */
- @Test
- public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPrivateOnlyCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
- final int expectedDefaultRequestSize = 2;
- final int expectedOemPrefRequestSize = 1;
- registerDefaultNetworkCallbacks();
-
- // The fallback as well as the OEM preference should now be tracked.
- assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mService.mNoServiceNetwork.network());
-
- // Bring up ethernet with OEM_PRIVATE. This will satisfy NET_CAPABILITY_OEM_PRIVATE.
- startOemManagedNetwork(false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mWiFiNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting OEM_PRIVATE will keep the fallback on cellular.
- // OEM_PRIVATE_ONLY not supporting a fallback now uses to the disconnected network.
- stopOemManagedNetwork();
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mService.mNoServiceNetwork.network());
-
- // Disconnecting cellular will put the fallback on null and pref on disconnected.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mService.mNoServiceNetwork.network());
-
- // default callbacks will be unregistered in tearDown
- }
-
- @Test
- public void testCapabilityWithOemNetworkPreference() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
- setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(networkPref);
- registerDefaultNetworkCallbacks();
-
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
-
- mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
- mSystemDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
- nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
- mDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
- nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
-
- // default callbacks will be unregistered in tearDown
- }
-
- @Test
- public void testSetOemNetworkPreferenceLogsRequest() throws Exception {
- mServiceContext.setPermission(DUMP, PERMISSION_GRANTED);
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
- final StringWriter stringWriter = new StringWriter();
- final String logIdentifier = "UPDATE INITIATED: OemNetworkPreferences";
- final Pattern pattern = Pattern.compile(logIdentifier);
-
- final int expectedNumLogs = 2;
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
-
- // Call twice to generate two logs.
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
- mService.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
-
- final String dumpOutput = stringWriter.toString();
- final Matcher matcher = pattern.matcher(dumpOutput);
- int count = 0;
- while (matcher.find()) {
- count++;
- }
- assertEquals(expectedNumLogs, count);
- }
-
- @Test
- public void testGetAllNetworkStateSnapshots() throws Exception {
- verifyNoNetwork();
-
- // Setup test cellular network with specified LinkProperties and NetworkCapabilities,
- // verify the content of the snapshot matches.
- final LinkProperties cellLp = new LinkProperties();
- final LinkAddress myIpv4Addr = new LinkAddress(InetAddress.getByName("192.0.2.129"), 25);
- final LinkAddress myIpv6Addr = new LinkAddress(InetAddress.getByName("2001:db8::1"), 64);
- cellLp.setInterfaceName("test01");
- cellLp.addLinkAddress(myIpv4Addr);
- cellLp.addLinkAddress(myIpv6Addr);
- cellLp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- cellLp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
- cellLp.addRoute(new RouteInfo(myIpv4Addr, null));
- cellLp.addRoute(new RouteInfo(myIpv6Addr, null));
- final NetworkCapabilities cellNcTemplate = new NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_CELLULAR).addCapability(NET_CAPABILITY_MMS).build();
-
- final TestNetworkCallback cellCb = new TestNetworkCallback();
- mCm.requestNetwork(new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(),
- cellCb);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp, cellNcTemplate);
- mCellNetworkAgent.connect(true);
- cellCb.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- List<NetworkStateSnapshot> snapshots = mCm.getAllNetworkStateSnapshots();
- assertLength(1, snapshots);
-
- // Compose the expected cellular snapshot for verification.
- final NetworkCapabilities cellNc =
- mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork());
- final NetworkStateSnapshot cellSnapshot = new NetworkStateSnapshot(
- mCellNetworkAgent.getNetwork(), cellNc, cellLp,
- null, ConnectivityManager.TYPE_MOBILE);
- assertEquals(cellSnapshot, snapshots.get(0));
-
- // Connect wifi and verify the snapshots.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- // Compose the expected wifi snapshot for verification.
- final NetworkCapabilities wifiNc =
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
- final NetworkStateSnapshot wifiSnapshot = new NetworkStateSnapshot(
- mWiFiNetworkAgent.getNetwork(), wifiNc, new LinkProperties(), null,
- ConnectivityManager.TYPE_WIFI);
-
- snapshots = mCm.getAllNetworkStateSnapshots();
- assertLength(2, snapshots);
- assertContainsAll(snapshots, cellSnapshot, wifiSnapshot);
-
- // Set cellular as suspended, verify the snapshots will not contain suspended networks.
- // TODO: Consider include SUSPENDED networks, which should be considered as
- // temporary shortage of connectivity of a connected network.
- mCellNetworkAgent.suspend();
- waitForIdle();
- snapshots = mCm.getAllNetworkStateSnapshots();
- assertLength(1, snapshots);
- assertEquals(wifiSnapshot, snapshots.get(0));
-
- // Disconnect wifi, verify the snapshots contain nothing.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
- snapshots = mCm.getAllNetworkStateSnapshots();
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertLength(0, snapshots);
-
- mCellNetworkAgent.resume();
- waitForIdle();
- snapshots = mCm.getAllNetworkStateSnapshots();
- assertLength(1, snapshots);
- assertEquals(cellSnapshot, snapshots.get(0));
-
- mCellNetworkAgent.disconnect();
- waitForIdle();
- verifyNoNetwork();
- mCm.unregisterNetworkCallback(cellCb);
- }
-
- // Cannot be part of MockNetworkFactory since it requires method of the test.
- private void expectNoRequestChanged(@NonNull MockNetworkFactory factory) {
- waitForIdle();
- factory.assertNoRequestChanged();
- }
-
- @Test
- public void testRegisterBestMatchingNetworkCallback_noIssueToFactory() throws Exception {
- // Prepare mock mms factory.
- final HandlerThread handlerThread = new HandlerThread("MockCellularFactory");
- handlerThread.start();
- NetworkCapabilities filter = new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_MMS);
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- testFactory.setScoreFilter(40);
-
- try {
- // Register the factory. It doesn't see the default request because its filter does
- // not include INTERNET.
- testFactory.register();
- expectNoRequestChanged(testFactory);
- testFactory.assertRequestCountEquals(0);
- // The factory won't try to start the network since the default request doesn't
- // match the filter (no INTERNET capability).
- assertFalse(testFactory.getMyStartRequested());
-
- // Register callback for listening best matching network. Verify that the request won't
- // be sent to factory.
- final TestNetworkCallback bestMatchingCb = new TestNetworkCallback();
- mCm.registerBestMatchingNetworkCallback(
- new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(),
- bestMatchingCb, mCsHandlerThread.getThreadHandler());
- bestMatchingCb.assertNoCallback();
- expectNoRequestChanged(testFactory);
- testFactory.assertRequestCountEquals(0);
- assertFalse(testFactory.getMyStartRequested());
-
- // Fire a normal mms request, verify the factory will only see the request.
- final TestNetworkCallback mmsNetworkCallback = new TestNetworkCallback();
- final NetworkRequest mmsRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_MMS).build();
- mCm.requestNetwork(mmsRequest, mmsNetworkCallback);
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
- assertTrue(testFactory.getMyStartRequested());
-
- // Unregister best matching callback, verify factory see no change.
- mCm.unregisterNetworkCallback(bestMatchingCb);
- expectNoRequestChanged(testFactory);
- testFactory.assertRequestCountEquals(1);
- assertTrue(testFactory.getMyStartRequested());
- } finally {
- testFactory.terminate();
- }
- }
-
- @Test
- public void testRegisterBestMatchingNetworkCallback_trackBestNetwork() throws Exception {
- final TestNetworkCallback bestMatchingCb = new TestNetworkCallback();
- mCm.registerBestMatchingNetworkCallback(
- new NetworkRequest.Builder().addCapability(NET_CAPABILITY_TRUSTED).build(),
- bestMatchingCb, mCsHandlerThread.getThreadHandler());
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- bestMatchingCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-
- // Change something on cellular to trigger capabilities changed, since the callback
- // only cares about the best network, verify it received nothing from cellular.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
- bestMatchingCb.assertNoCallback();
-
- // Make cellular the best network again, verify the callback now tracks cellular.
- mWiFiNetworkAgent.adjustScore(-50);
- bestMatchingCb.expectAvailableCallbacksValidated(mCellNetworkAgent);
-
- // Make cellular temporary non-trusted, which will not satisfying the request.
- // Verify the callback switch from/to the other network accordingly.
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
- bestMatchingCb.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_TRUSTED);
- bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mCellNetworkAgent);
-
- // Verify the callback doesn't care about wifi disconnect.
- mWiFiNetworkAgent.disconnect();
- bestMatchingCb.assertNoCallback();
- mCellNetworkAgent.disconnect();
- bestMatchingCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- }
-
- private UidRangeParcel[] uidRangeFor(final UserHandle handle) {
- UidRange range = UidRange.createForUser(handle);
- return new UidRangeParcel[] { new UidRangeParcel(range.start, range.stop) };
- }
-
- private static class TestOnCompleteListener implements Runnable {
- final class OnComplete {}
- final ArrayTrackRecord<OnComplete>.ReadHead mHistory =
- new ArrayTrackRecord<OnComplete>().newReadHead();
-
- @Override
- public void run() {
- mHistory.add(new OnComplete());
- }
-
- public void expectOnComplete() {
- assertNotNull(mHistory.poll(TIMEOUT_MS, it -> true));
- }
- }
-
- private TestNetworkAgentWrapper makeEnterpriseNetworkAgent() throws Exception {
- final NetworkCapabilities workNc = new NetworkCapabilities();
- workNc.addCapability(NET_CAPABILITY_ENTERPRISE);
- workNc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- return new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), workNc);
- }
-
- private TestNetworkCallback mEnterpriseCallback;
- private UserHandle setupEnterpriseNetwork() {
- final UserHandle userHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
- mServiceContext.setWorkProfile(userHandle, true);
-
- // File a request to avoid the enterprise network being disconnected as soon as the default
- // request goes away – it would make impossible to test that networkRemoveUidRanges
- // is called, as the network would disconnect first for lack of a request.
- mEnterpriseCallback = new TestNetworkCallback();
- final NetworkRequest keepUpRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_ENTERPRISE)
- .build();
- mCm.requestNetwork(keepUpRequest, mEnterpriseCallback);
- return userHandle;
- }
-
- private void maybeTearDownEnterpriseNetwork() {
- if (null != mEnterpriseCallback) {
- mCm.unregisterNetworkCallback(mEnterpriseCallback);
- }
- }
-
- /**
- * Make sure per-profile networking preference behaves as expected when the enterprise network
- * goes up and down while the preference is active. Make sure they behave as expected whether
- * there is a general default network or not.
- */
- @Test
- public void testPreferenceForUserNetworkUpDown() throws Exception {
- final InOrder inOrder = inOrder(mMockNetd);
- final UserHandle testHandle = setupEnterpriseNetwork();
- registerDefaultNetworkCallbacks();
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
-
-
- final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
-
- // Setting a network preference for this user will create a new set of routing rules for
- // the UID range that corresponds to this user, so as to define the default network
- // for these apps separately. This is true because the multi-layer request relevant to
- // this UID range contains a TRACK_DEFAULT, so the range will be moved through UID-specific
- // rules to the correct network – in this case the system default network. The case where
- // the default network for the profile happens to be the same as the system default
- // is not handled specially, the rules are always active as long as a preference is set.
- inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
-
- // The enterprise network is not ready yet.
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- mProfileDefaultNetworkCallback);
-
- final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
- workAgent.connect(false);
-
- mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent);
- mSystemDefaultNetworkCallback.assertNoCallback();
- mDefaultNetworkCallback.assertNoCallback();
- inOrder.verify(mMockNetd).networkCreate(
- nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle));
- inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
-
- // Make sure changes to the work agent send callbacks to the app in the work profile, but
- // not to the other apps.
- workAgent.setNetworkValid(true /* isStrictMode */);
- workAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent,
- nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED)
- && nc.hasCapability(NET_CAPABILITY_ENTERPRISE));
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
-
- workAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
- mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent, nc ->
- nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
-
- // Conversely, change a capability on the system-wide default network and make sure
- // that only the apps outside of the work profile receive the callbacks.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
- mSystemDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
- nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
- mDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
- nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
- mProfileDefaultNetworkCallback.assertNoCallback();
-
- // Disconnect and reconnect the system-wide default network and make sure that the
- // apps on this network see the appropriate callbacks, and the app on the work profile
- // doesn't because it continues to use the enterprise network.
- mCellNetworkAgent.disconnect();
- mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- mProfileDefaultNetworkCallback.assertNoCallback();
- inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mProfileDefaultNetworkCallback.assertNoCallback();
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
-
- // When the agent disconnects, test that the app on the work profile falls back to the
- // default network.
- workAgent.disconnect();
- mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent);
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
- inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId);
-
- mCellNetworkAgent.disconnect();
- mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
-
- // Waiting for the handler to be idle before checking for networkDestroy is necessary
- // here because ConnectivityService calls onLost before the network is fully torn down.
- waitForIdle();
- inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
-
- // If the control comes here, callbacks seem to behave correctly in the presence of
- // a default network when the enterprise network goes up and down. Now, make sure they
- // also behave correctly in the absence of a system-wide default network.
- final TestNetworkAgentWrapper workAgent2 = makeEnterpriseNetworkAgent();
- workAgent2.connect(false);
-
- mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent2);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- workAgent2.getNetwork().netId, INetd.PERMISSION_SYSTEM));
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent2.getNetwork().netId,
- uidRangeFor(testHandle));
-
- workAgent2.setNetworkValid(true /* isStrictMode */);
- workAgent2.mNetworkMonitor.forceReevaluation(Process.myUid());
- mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent2,
- nc -> nc.hasCapability(NET_CAPABILITY_ENTERPRISE)
- && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
-
- // When the agent disconnects, test that the app on the work profile falls back to the
- // default network.
- workAgent2.disconnect();
- mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent2);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkDestroy(workAgent2.getNetwork().netId);
-
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- mProfileDefaultNetworkCallback);
-
- // Callbacks will be unregistered by tearDown()
- }
-
- /**
- * Test that, in a given networking context, calling setPreferenceForUser to set per-profile
- * defaults on then off works as expected.
- */
- @Test
- public void testSetPreferenceForUserOnOff() throws Exception {
- final InOrder inOrder = inOrder(mMockNetd);
- final UserHandle testHandle = setupEnterpriseNetwork();
-
- // Connect both a regular cell agent and an enterprise network first.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
- workAgent.connect(true);
-
- final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle));
-
- registerDefaultNetworkCallbacks();
-
- mSystemDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
-
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_DEFAULT,
- r -> r.run(), listener);
- listener.expectOnComplete();
-
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkRemoveUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle));
-
- workAgent.disconnect();
- mCellNetworkAgent.disconnect();
-
- // Callbacks will be unregistered by tearDown()
- }
-
- /**
- * Test per-profile default networks for two different profiles concurrently.
- */
- @Test
- public void testSetPreferenceForTwoProfiles() throws Exception {
- final InOrder inOrder = inOrder(mMockNetd);
- final UserHandle testHandle2 = setupEnterpriseNetwork();
- final UserHandle testHandle4 = UserHandle.of(TEST_WORK_PROFILE_USER_ID + 2);
- mServiceContext.setWorkProfile(testHandle4, true);
- registerDefaultNetworkCallbacks();
-
- final TestNetworkCallback app4Cb = new TestNetworkCallback();
- final int testWorkProfileAppUid4 =
- UserHandle.getUid(testHandle4.getIdentifier(), TEST_APP_ID);
- registerDefaultNetworkCallbackAsUid(app4Cb, testWorkProfileAppUid4);
-
- // Connect both a regular cell agent and an enterprise network first.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
- workAgent.connect(true);
-
- mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- app4Cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
-
- final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle2));
-
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- app4Cb);
-
- mCm.setProfileNetworkPreference(testHandle4, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle4));
-
- app4Cb.expectAvailableCallbacksValidated(workAgent);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- mProfileDefaultNetworkCallback);
-
- mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_DEFAULT,
- r -> r.run(), listener);
- listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkRemoveUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle2));
-
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- app4Cb);
-
- workAgent.disconnect();
- mCellNetworkAgent.disconnect();
-
- mCm.unregisterNetworkCallback(app4Cb);
- // Other callbacks will be unregistered by tearDown()
- }
-
- @Test
- public void testProfilePreferenceRemovedUponUserRemoved() throws Exception {
- final InOrder inOrder = inOrder(mMockNetd);
- final UserHandle testHandle = setupEnterpriseNetwork();
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
- inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
-
- final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
- removedIntent.putExtra(Intent.EXTRA_USER, testHandle);
- processBroadcast(removedIntent);
-
- inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
- }
-
- /**
- * Make sure that OEM preference and per-profile preference can't be used at the same
- * time and throw ISE if tried
- */
- @Test
- public void testOemPreferenceAndProfilePreferenceExclusive() throws Exception {
- final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
- mServiceContext.setWorkProfile(testHandle, true);
- final TestOnCompleteListener listener = new TestOnCompleteListener();
-
- setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY);
- assertThrows("Should not be able to set per-profile pref while OEM prefs present",
- IllegalStateException.class, () ->
- mCm.setProfileNetworkPreference(testHandle,
- PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener));
-
- // Empty the OEM prefs
- final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
- final OemNetworkPreferences emptyOemPref = new OemNetworkPreferences.Builder().build();
- mService.setOemNetworkPreference(emptyOemPref, oemPrefListener);
- oemPrefListener.expectOnComplete();
-
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
- assertThrows("Should not be able to set OEM prefs while per-profile pref is on",
- IllegalStateException.class , () ->
- mService.setOemNetworkPreference(emptyOemPref, oemPrefListener));
- }
-
- /**
- * Make sure wrong preferences for per-profile default networking are rejected.
- */
- @Test
- public void testProfileNetworkPrefWrongPreference() throws Exception {
- final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
- mServiceContext.setWorkProfile(testHandle, true);
- assertThrows("Should not be able to set an illegal preference",
- IllegalArgumentException.class,
- () -> mCm.setProfileNetworkPreference(testHandle,
- PROFILE_NETWORK_PREFERENCE_ENTERPRISE + 1, null, null));
- }
-
- /**
- * Make sure requests for per-profile default networking for a non-work profile are
- * rejected
- */
- @Test
- public void testProfileNetworkPrefWrongProfile() throws Exception {
- final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
- mServiceContext.setWorkProfile(testHandle, false);
- assertThrows("Should not be able to set a user pref for a non-work profile",
- IllegalArgumentException.class , () ->
- mCm.setProfileNetworkPreference(testHandle,
- PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null, null));
- }
-
- @Test
- public void testSubIdsClearedWithoutNetworkFactoryPermission() throws Exception {
- mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setSubscriptionIds(Collections.singleton(Process.myUid()));
-
- final NetworkCapabilities result =
- mService.networkCapabilitiesRestrictedForCallerPermissions(
- nc, Process.myPid(), Process.myUid());
- assertTrue(result.getSubscriptionIds().isEmpty());
- }
-
- @Test
- public void testSubIdsExistWithNetworkFactoryPermission() throws Exception {
- mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
-
- final Set<Integer> subIds = Collections.singleton(Process.myUid());
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setSubscriptionIds(subIds);
-
- final NetworkCapabilities result =
- mService.networkCapabilitiesRestrictedForCallerPermissions(
- nc, Process.myPid(), Process.myUid());
- assertEquals(subIds, result.getSubscriptionIds());
- }
-
- private NetworkRequest getRequestWithSubIds() {
- return new NetworkRequest.Builder()
- .setSubscriptionIds(Collections.singleton(Process.myUid()))
- .build();
- }
-
- @Test
- public void testNetworkRequestWithSubIdsWithNetworkFactoryPermission() throws Exception {
- mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
- final NetworkCallback networkCallback1 = new NetworkCallback();
- final NetworkCallback networkCallback2 = new NetworkCallback();
-
- mCm.requestNetwork(getRequestWithSubIds(), networkCallback1);
- mCm.requestNetwork(getRequestWithSubIds(), pendingIntent);
- mCm.registerNetworkCallback(getRequestWithSubIds(), networkCallback2);
-
- mCm.unregisterNetworkCallback(networkCallback1);
- mCm.releaseNetworkRequest(pendingIntent);
- mCm.unregisterNetworkCallback(networkCallback2);
- }
-
- @Test
- public void testNetworkRequestWithSubIdsWithoutNetworkFactoryPermission() throws Exception {
- mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
-
- final Class<SecurityException> expected = SecurityException.class;
- assertThrows(
- expected, () -> mCm.requestNetwork(getRequestWithSubIds(), new NetworkCallback()));
- assertThrows(expected, () -> mCm.requestNetwork(getRequestWithSubIds(), pendingIntent));
- assertThrows(
- expected,
- () -> mCm.registerNetworkCallback(getRequestWithSubIds(), new NetworkCallback()));
- }
-
- /**
- * Validate request counts are counted accurately on setProfileNetworkPreference on set/replace.
- */
- @Test
- public void testProfileNetworkPrefCountsRequestsCorrectlyOnSet() throws Exception {
- final UserHandle testHandle = setupEnterpriseNetwork();
- testRequestCountLimits(() -> {
- // Set initially to test the limit prior to having existing requests.
- final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- Runnable::run, listener);
- listener.expectOnComplete();
-
- // re-set so as to test the limit as part of replacing existing requests.
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- Runnable::run, listener);
- listener.expectOnComplete();
- });
- }
-
- /**
- * Validate request counts are counted accurately on setOemNetworkPreference on set/replace.
- */
- @Test
- public void testSetOemNetworkPreferenceCountsRequestsCorrectlyOnSet() throws Exception {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
- testRequestCountLimits(() -> {
- // Set initially to test the limit prior to having existing requests.
- final TestOemListenerCallback listener = new TestOemListenerCallback();
- mService.setOemNetworkPreference(
- createDefaultOemNetworkPreferences(networkPref), listener);
- listener.expectOnComplete();
-
- // re-set so as to test the limit as part of replacing existing requests.
- mService.setOemNetworkPreference(
- createDefaultOemNetworkPreferences(networkPref), listener);
- listener.expectOnComplete();
- });
- }
-
- private void testRequestCountLimits(@NonNull final Runnable r) throws Exception {
- final ArraySet<TestNetworkCallback> callbacks = new ArraySet<>();
- try {
- final int requestCount = mService.mSystemNetworkRequestCounter
- .mUidToNetworkRequestCount.get(Process.myUid());
- // The limit is hit when total requests <= limit.
- final int maxCount =
- ConnectivityService.MAX_NETWORK_REQUESTS_PER_SYSTEM_UID - requestCount;
- // Need permission so registerDefaultNetworkCallback uses mSystemNetworkRequestCounter
- withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
- for (int i = 1; i < maxCount - 1; i++) {
- final TestNetworkCallback cb = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(cb);
- callbacks.add(cb);
- }
-
- // Code to run to check if it triggers a max request count limit error.
- r.run();
- });
- } finally {
- for (final TestNetworkCallback cb : callbacks) {
- mCm.unregisterNetworkCallback(cb);
- }
- }
- }
-}