Merge "[BR14] Tracker Data Saver status in ConnectivityService" into main am: 5ad399d8c3
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/2856948 Change-Id: I78fbb447cb931a95f85e5fc4ea6e18c5de7b0030 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -16,8 +16,6 @@
|
|||||||
package android.net;
|
package android.net;
|
||||||
|
|
||||||
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
|
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
|
||||||
import static android.content.pm.ApplicationInfo.FLAG_PERSISTENT;
|
|
||||||
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
|
|
||||||
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
|
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
|
||||||
import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
|
import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
|
||||||
import static android.net.NetworkRequest.Type.LISTEN;
|
import static android.net.NetworkRequest.Type.LISTEN;
|
||||||
@@ -27,8 +25,6 @@ import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
|
|||||||
import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
|
import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
|
||||||
import static android.net.QosCallback.QosCallbackRegistrationException;
|
import static android.net.QosCallback.QosCallbackRegistrationException;
|
||||||
|
|
||||||
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
|
||||||
|
|
||||||
import android.annotation.CallbackExecutor;
|
import android.annotation.CallbackExecutor;
|
||||||
import android.annotation.FlaggedApi;
|
import android.annotation.FlaggedApi;
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
@@ -41,16 +37,12 @@ import android.annotation.SdkConstant.SdkConstantType;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
import android.annotation.SystemService;
|
import android.annotation.SystemService;
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.Application;
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.compat.annotation.UnsupportedAppUsage;
|
import android.compat.annotation.UnsupportedAppUsage;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.net.ConnectivityDiagnosticsManager.DataStallReport.DetectionMethod;
|
import android.net.ConnectivityDiagnosticsManager.DataStallReport.DetectionMethod;
|
||||||
import android.net.IpSecManager.UdpEncapsulationSocket;
|
import android.net.IpSecManager.UdpEncapsulationSocket;
|
||||||
import android.net.SocketKeepalive.Callback;
|
import android.net.SocketKeepalive.Callback;
|
||||||
@@ -82,8 +74,6 @@ import android.util.Range;
|
|||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
|
||||||
import com.android.modules.utils.build.SdkLevel;
|
|
||||||
|
|
||||||
import libcore.net.event.NetworkEventDispatcher;
|
import libcore.net.event.NetworkEventDispatcher;
|
||||||
|
|
||||||
@@ -105,7 +95,6 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.RejectedExecutionException;
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that answers queries about the state of network connectivity. It also
|
* Class that answers queries about the state of network connectivity. It also
|
||||||
@@ -6261,90 +6250,6 @@ public class ConnectivityManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper class to track data saver status.
|
|
||||||
*
|
|
||||||
* The class will fetch current data saver status from {@link NetworkPolicyManager} when
|
|
||||||
* initialized, and listening for status changed intent to cache the latest status.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@TargetApi(Build.VERSION_CODES.TIRAMISU) // RECEIVER_NOT_EXPORTED requires T.
|
|
||||||
@VisibleForTesting(visibility = PRIVATE)
|
|
||||||
public static class DataSaverStatusTracker extends BroadcastReceiver {
|
|
||||||
private static final Object sDataSaverStatusTrackerLock = new Object();
|
|
||||||
|
|
||||||
private static volatile DataSaverStatusTracker sInstance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a static instance of the class.
|
|
||||||
*
|
|
||||||
* @param context A {@link Context} for initialization. Note that since the data saver
|
|
||||||
* status is global on a device, passing any context is equivalent.
|
|
||||||
* @return The static instance of a {@link DataSaverStatusTracker}.
|
|
||||||
*/
|
|
||||||
public static DataSaverStatusTracker getInstance(@NonNull Context context) {
|
|
||||||
if (sInstance == null) {
|
|
||||||
synchronized (sDataSaverStatusTrackerLock) {
|
|
||||||
if (sInstance == null) {
|
|
||||||
sInstance = new DataSaverStatusTracker(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final NetworkPolicyManager mNpm;
|
|
||||||
// The value updates on the caller's binder thread or UI thread.
|
|
||||||
private final AtomicBoolean mIsDataSaverEnabled;
|
|
||||||
|
|
||||||
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
|
|
||||||
public DataSaverStatusTracker(final Context context) {
|
|
||||||
// To avoid leaks, take the application context.
|
|
||||||
final Context appContext;
|
|
||||||
if (context instanceof Application) {
|
|
||||||
appContext = context;
|
|
||||||
} else {
|
|
||||||
appContext = context.getApplicationContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((appContext.getApplicationInfo().flags & FLAG_PERSISTENT) == 0
|
|
||||||
&& (appContext.getApplicationInfo().flags & FLAG_SYSTEM) == 0) {
|
|
||||||
throw new IllegalStateException("Unexpected caller: "
|
|
||||||
+ appContext.getApplicationInfo().packageName);
|
|
||||||
}
|
|
||||||
|
|
||||||
mNpm = appContext.getSystemService(NetworkPolicyManager.class);
|
|
||||||
final IntentFilter filter = new IntentFilter(
|
|
||||||
ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED);
|
|
||||||
// The receiver should not receive broadcasts from other Apps.
|
|
||||||
appContext.registerReceiver(this, filter, Context.RECEIVER_NOT_EXPORTED);
|
|
||||||
mIsDataSaverEnabled = new AtomicBoolean();
|
|
||||||
updateDataSaverEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Runs on caller's UI thread.
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (intent.getAction().equals(ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED)) {
|
|
||||||
updateDataSaverEnabled();
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Unexpected intent " + intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getDataSaverEnabled() {
|
|
||||||
return mIsDataSaverEnabled.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateDataSaverEnabled() {
|
|
||||||
// Uid doesn't really matter, but use a fixed UID to make things clearer.
|
|
||||||
final int dataSaverForCallerUid = mNpm.getRestrictBackgroundStatus(Process.SYSTEM_UID);
|
|
||||||
mIsDataSaverEnabled.set(dataSaverForCallerUid
|
|
||||||
!= ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return whether the network is blocked for the given uid and metered condition.
|
* Return whether the network is blocked for the given uid and metered condition.
|
||||||
*
|
*
|
||||||
@@ -6370,17 +6275,12 @@ public class ConnectivityManager {
|
|||||||
@RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
|
@RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
|
||||||
public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
|
public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
|
||||||
final BpfNetMapsReader reader = BpfNetMapsReader.getInstance();
|
final BpfNetMapsReader reader = BpfNetMapsReader.getInstance();
|
||||||
|
// Note that before V, the data saver status in bpf is written by ConnectivityService
|
||||||
final boolean isDataSaverEnabled;
|
// when receiving {@link #ACTION_RESTRICT_BACKGROUND_CHANGED}. Thus,
|
||||||
if (SdkLevel.isAtLeastV()) {
|
// the status is not synchronized.
|
||||||
isDataSaverEnabled = reader.getDataSaverEnabled();
|
// On V+, the data saver status is set by platform code when enabling/disabling
|
||||||
} else {
|
// data saver, which is synchronized.
|
||||||
final DataSaverStatusTracker dataSaverStatusTracker =
|
return reader.isUidNetworkingBlocked(uid, isNetworkMetered, reader.getDataSaverEnabled());
|
||||||
DataSaverStatusTracker.getInstance(mContext);
|
|
||||||
isDataSaverEnabled = dataSaverStatusTracker.getDataSaverEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader.isUidNetworkingBlocked(uid, isNetworkMetered, isDataSaverEnabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTI
|
|||||||
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
|
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
|
||||||
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
|
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
|
||||||
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
|
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
|
||||||
|
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
|
||||||
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
|
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
|
||||||
import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN;
|
import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN;
|
||||||
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
|
import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
|
||||||
@@ -1770,6 +1771,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mUserAllContext.registerReceiver(mPackageIntentReceiver, packageIntentFilter,
|
mUserAllContext.registerReceiver(mPackageIntentReceiver, packageIntentFilter,
|
||||||
null /* broadcastPermission */, mHandler);
|
null /* broadcastPermission */, mHandler);
|
||||||
|
|
||||||
|
// This is needed for pre-V devices to propagate the data saver status
|
||||||
|
// to the BPF map. This isn't supported before Android T because BPF maps are
|
||||||
|
// unsupported, and it's also unnecessary on Android V and later versions,
|
||||||
|
// as the platform code handles data saver bit updates. Additionally, checking
|
||||||
|
// the initial data saver status here is superfluous because the intent won't
|
||||||
|
// be sent until the system is ready.
|
||||||
|
if (mDeps.isAtLeastT() && !mDeps.isAtLeastV()) {
|
||||||
|
final IntentFilter dataSaverIntentFilter =
|
||||||
|
new IntentFilter(ACTION_RESTRICT_BACKGROUND_CHANGED);
|
||||||
|
mUserAllContext.registerReceiver(mDataSaverReceiver, dataSaverIntentFilter,
|
||||||
|
null /* broadcastPermission */, mHandler);
|
||||||
|
}
|
||||||
|
|
||||||
// TrackMultiNetworkActivities feature should be enabled by trunk stable flag.
|
// TrackMultiNetworkActivities feature should be enabled by trunk stable flag.
|
||||||
// But reading the trunk stable flags from mainline modules is not supported yet.
|
// But reading the trunk stable flags from mainline modules is not supported yet.
|
||||||
// So enabling this feature on V+ release.
|
// So enabling this feature on V+ release.
|
||||||
@@ -7051,6 +7065,32 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
|
private final BroadcastReceiver mDataSaverReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (mDeps.isAtLeastV()) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"data saver status should be updated from platform");
|
||||||
|
}
|
||||||
|
ensureRunningOnConnectivityServiceThread();
|
||||||
|
switch (intent.getAction()) {
|
||||||
|
case ACTION_RESTRICT_BACKGROUND_CHANGED:
|
||||||
|
// If the uid is present in the deny list, the API will consistently
|
||||||
|
// return ENABLED. To retrieve the global switch status, the system
|
||||||
|
// uid is chosen because it will never be included in the deny list.
|
||||||
|
final int dataSaverForSystemUid =
|
||||||
|
mPolicyManager.getRestrictBackgroundStatus(Process.SYSTEM_UID);
|
||||||
|
final boolean isDataSaverEnabled = (dataSaverForSystemUid
|
||||||
|
!= ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED);
|
||||||
|
mBpfNetMaps.setDataSaverEnabled(isDataSaverEnabled);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.wtf(TAG, "received unexpected intent: " + intent.getAction());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
|
private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
|
||||||
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
|
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
|
||||||
|
|
||||||
@@ -12988,7 +13028,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.TIRAMISU)
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
@Override
|
@Override
|
||||||
public void setDataSaverEnabled(final boolean enable) {
|
public void setDataSaverEnabled(final boolean enable) {
|
||||||
enforceNetworkStackOrSettingsPermission();
|
enforceNetworkStackOrSettingsPermission();
|
||||||
|
|||||||
@@ -16,13 +16,6 @@
|
|||||||
|
|
||||||
package android.net;
|
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.ConnectivityManager.TYPE_NONE;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
|
||||||
@@ -46,7 +39,6 @@ import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
|
|||||||
|
|
||||||
import static com.android.testutils.MiscAsserts.assertThrows;
|
import static com.android.testutils.MiscAsserts.assertThrows;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
@@ -70,10 +62,7 @@ import static org.mockito.Mockito.when;
|
|||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.net.ConnectivityManager.DataSaverStatusTracker;
|
|
||||||
import android.net.ConnectivityManager.NetworkCallback;
|
import android.net.ConnectivityManager.NetworkCallback;
|
||||||
import android.os.Build.VERSION_CODES;
|
import android.os.Build.VERSION_CODES;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -527,44 +516,6 @@ public class ConnectivityManagerTest {
|
|||||||
+ " attempts", ref.get());
|
+ " attempts", ref.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@DevSdkIgnoreRule.IgnoreAfter(VERSION_CODES.UPSIDE_DOWN_CAKE)
|
|
||||||
@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) {
|
private <T> void mockService(Class<T> clazz, String name, T service) {
|
||||||
doReturn(service).when(mCtx).getSystemService(name);
|
doReturn(service).when(mCtx).getSystemService(name);
|
||||||
doReturn(name).when(mCtx).getSystemServiceName(clazz);
|
doReturn(name).when(mCtx).getSystemServiceName(clazz);
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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 android.content.Intent
|
||||||
|
import android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED
|
||||||
|
import android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED
|
||||||
|
import android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED
|
||||||
|
import android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
|
||||||
|
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||||
|
import com.android.testutils.DevSdkIgnoreRunner
|
||||||
|
import com.android.testutils.visibleOnHandlerThread
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentMatchers.anyBoolean
|
||||||
|
import org.mockito.ArgumentMatchers.anyInt
|
||||||
|
import org.mockito.Mockito.doReturn
|
||||||
|
import org.mockito.Mockito.inOrder
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
|
||||||
|
@RunWith(DevSdkIgnoreRunner::class)
|
||||||
|
@SmallTest
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.S_V2) // Bpf only supports in T+.
|
||||||
|
class CSBpfNetMapsTest : CSTest() {
|
||||||
|
@get:Rule
|
||||||
|
val ignoreRule = DevSdkIgnoreRule()
|
||||||
|
|
||||||
|
@IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||||
|
@Test
|
||||||
|
fun testCSTrackDataSaverBeforeV() {
|
||||||
|
val inOrder = inOrder(bpfNetMaps)
|
||||||
|
mockDataSaverStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED)
|
||||||
|
inOrder.verify(bpfNetMaps).setDataSaverEnabled(true)
|
||||||
|
mockDataSaverStatus(RESTRICT_BACKGROUND_STATUS_DISABLED)
|
||||||
|
inOrder.verify(bpfNetMaps).setDataSaverEnabled(false)
|
||||||
|
mockDataSaverStatus(RESTRICT_BACKGROUND_STATUS_ENABLED)
|
||||||
|
inOrder.verify(bpfNetMaps).setDataSaverEnabled(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data Saver Status is updated from platform code in V+.
|
||||||
|
@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||||
|
@Test
|
||||||
|
fun testCSTrackDataSaverAboveU() {
|
||||||
|
listOf(RESTRICT_BACKGROUND_STATUS_WHITELISTED, RESTRICT_BACKGROUND_STATUS_ENABLED,
|
||||||
|
RESTRICT_BACKGROUND_STATUS_DISABLED).forEach {
|
||||||
|
mockDataSaverStatus(it)
|
||||||
|
verify(bpfNetMaps, never()).setDataSaverEnabled(anyBoolean())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun mockDataSaverStatus(status: Int) {
|
||||||
|
doReturn(status).`when`(context.networkPolicyManager).getRestrictBackgroundStatus(anyInt())
|
||||||
|
// While the production code dispatches the intent on the handler thread,
|
||||||
|
// The test would dispatch the intent in the caller thread. Make it dispatch
|
||||||
|
// on the handler thread to match production behavior.
|
||||||
|
visibleOnHandlerThread(csHandler) {
|
||||||
|
context.sendBroadcast(Intent(ACTION_RESTRICT_BACKGROUND_CHANGED))
|
||||||
|
}
|
||||||
|
waitForIdle()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user