[BR06] Support check whether network is blocked by data saver

This change adds a DataSaverStatusTracker, which is a helper
class to continuously track data saver status through NPMS
public API and intents. ConnectivityManager#isUidNetworkingBlocked
would use this cached information along with bpf maps to decide
whether networking of an uid is blocked.

Test: atest FrameworksNetTests:android.net.connectivity.android.net.BpfNetMapsReaderTest
Test: atest ConnectivityCoverageTests:android.net.connectivity.android.net.ConnectivityManagerTest
Bug: 297836825
Change-Id: I7e13191759430f3ea1f4dec7facc02f16be7146d
This commit is contained in:
Junyu Lai
2023-09-06 19:10:02 +08:00
parent e003152e2c
commit c3dc5b6222
4 changed files with 246 additions and 18 deletions

View File

@@ -16,6 +16,13 @@
package android.net;
import static android.content.Context.RECEIVER_NOT_EXPORTED;
import static android.content.pm.ApplicationInfo.FLAG_PERSISTENT;
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
@@ -39,6 +46,7 @@ import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
import static com.android.testutils.MiscAsserts.assertThrows;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -51,6 +59,7 @@ import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.after;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -61,7 +70,10 @@ import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.net.ConnectivityManager.DataSaverStatusTracker;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -95,6 +107,7 @@ public class ConnectivityManagerTest {
@Mock Context mCtx;
@Mock IConnectivityManager mService;
@Mock NetworkPolicyManager mNpm;
@Before
public void setUp() {
@@ -510,4 +523,54 @@ public class ConnectivityManagerTest {
assertNull("ConnectivityManager weak reference still not null after " + attempts
+ " attempts", ref.get());
}
@Test
public void testDataSaverStatusTracker() {
mockService(NetworkPolicyManager.class, Context.NETWORK_POLICY_SERVICE, mNpm);
// Mock proper application info.
doReturn(mCtx).when(mCtx).getApplicationContext();
final ApplicationInfo mockAppInfo = new ApplicationInfo();
mockAppInfo.flags = FLAG_PERSISTENT | FLAG_SYSTEM;
doReturn(mockAppInfo).when(mCtx).getApplicationInfo();
// Enable data saver.
doReturn(RESTRICT_BACKGROUND_STATUS_ENABLED).when(mNpm)
.getRestrictBackgroundStatus(anyInt());
final DataSaverStatusTracker tracker = new DataSaverStatusTracker(mCtx);
// Verify the data saver status is correct right after initialization.
assertTrue(tracker.getDataSaverEnabled());
// Verify the tracker register receiver with expected intent filter.
final ArgumentCaptor<IntentFilter> intentFilterCaptor =
ArgumentCaptor.forClass(IntentFilter.class);
verify(mCtx).registerReceiver(
any(), intentFilterCaptor.capture(), eq(RECEIVER_NOT_EXPORTED));
assertEquals(ACTION_RESTRICT_BACKGROUND_CHANGED,
intentFilterCaptor.getValue().getAction(0));
// Mock data saver status changed event and verify the tracker tracks the
// status accordingly.
doReturn(RESTRICT_BACKGROUND_STATUS_DISABLED).when(mNpm)
.getRestrictBackgroundStatus(anyInt());
tracker.onReceive(mCtx, new Intent(ACTION_RESTRICT_BACKGROUND_CHANGED));
assertFalse(tracker.getDataSaverEnabled());
doReturn(RESTRICT_BACKGROUND_STATUS_WHITELISTED).when(mNpm)
.getRestrictBackgroundStatus(anyInt());
tracker.onReceive(mCtx, new Intent(ACTION_RESTRICT_BACKGROUND_CHANGED));
assertTrue(tracker.getDataSaverEnabled());
}
private <T> void mockService(Class<T> clazz, String name, T service) {
doReturn(service).when(mCtx).getSystemService(name);
doReturn(name).when(mCtx).getSystemServiceName(clazz);
// If the test suite uses the inline mock maker library, such as for coverage tests,
// then the final version of getSystemService must also be mocked, as the real
// method will not be called by the test and null object is returned since no mock.
// Otherwise, mocking a final method will fail the test.
if (mCtx.getSystemService(clazz) == null) {
doReturn(service).when(mCtx).getSystemService(clazz);
}
}
}