Merge "Fix kernelToTag import in NetworkStatsFactoryTest."
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index c0e6749..ecbaf61 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -65,6 +65,7 @@
android_library {
name: "TetheringApiCurrentLib",
defaults: [
+ "ConnectivityNextEnableDefaults",
"TetheringAndroidLibraryDefaults",
"TetheringApiLevel"
],
@@ -159,7 +160,7 @@
// Non-updatable tethering running in the system server process for devices not using the module
android_app {
name: "InProcessTethering",
- defaults: ["TetheringAppDefaults", "TetheringApiLevel"],
+ defaults: ["TetheringAppDefaults", "TetheringApiLevel", "ConnectivityNextEnableDefaults"],
static_libs: ["TetheringApiCurrentLib"],
certificate: "platform",
manifest: "AndroidManifest_InProcess.xml",
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index fa7dfa9..8137551 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -249,6 +249,7 @@
import com.android.net.module.util.PermissionUtils;
import com.android.net.module.util.netlink.InetDiagMessage;
import com.android.server.connectivity.AutodestructReference;
+import com.android.server.connectivity.CarrierPrivilegeAuthenticator;
import com.android.server.connectivity.ConnectivityFlags;
import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
@@ -593,6 +594,13 @@
// Handle private DNS validation status updates.
private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38;
+ /**
+ * used to remove a network request, either a listener or a real request and call unavailable
+ * arg1 = UID of caller
+ * obj = NetworkRequest
+ */
+ private static final int EVENT_RELEASE_NETWORK_REQUEST_AND_CALL_UNAVAILABLE = 39;
+
/**
* Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
* been tested.
@@ -760,6 +768,7 @@
private Set<String> mWolSupportedInterfaces;
private final TelephonyManager mTelephonyManager;
+ private final CarrierPrivilegeAuthenticator mCarrierPrivilegeAuthenticator;
private final AppOpsManager mAppOpsManager;
private final LocationPermissionChecker mLocationPermissionChecker;
@@ -1406,6 +1415,12 @@
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext);
+ if (SdkLevel.isAtLeastT()) {
+ mCarrierPrivilegeAuthenticator =
+ new CarrierPrivilegeAuthenticator(mContext, mTelephonyManager);
+ } else {
+ mCarrierPrivilegeAuthenticator = null;
+ }
// To ensure uid state is synchronized with Network Policy, register for
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
@@ -4140,6 +4155,15 @@
}
}
+ private boolean hasCarrierPrivilegeForNetworkRequest(int callingUid,
+ NetworkRequest networkRequest) {
+ if (SdkLevel.isAtLeastT() && mCarrierPrivilegeAuthenticator != null) {
+ return mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(callingUid,
+ networkRequest);
+ }
+ return false;
+ }
+
private void handleRegisterNetworkRequestWithIntent(@NonNull final Message msg) {
final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj);
// handleRegisterNetworkRequestWithIntent() doesn't apply to multilayer requests.
@@ -4163,6 +4187,7 @@
private void handleRegisterNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
ensureRunningOnConnectivityServiceThread();
+ NetworkRequest requestToBeReleased = null;
for (final NetworkRequestInfo nri : nris) {
mNetworkRequestInfoLogs.log("REGISTER " + nri);
checkNrisConsistency(nri);
@@ -4177,7 +4202,15 @@
}
}
}
+ if (req.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
+ if (!hasCarrierPrivilegeForNetworkRequest(nri.mUid, req)
+ && !checkConnectivityRestrictedNetworksPermission(
+ nri.mPid, nri.mUid)) {
+ requestToBeReleased = req;
+ }
+ }
}
+
// If this NRI has a satisfier already, it is replacing an older request that
// has been removed. Track it.
final NetworkRequest activeRequest = nri.getActiveRequest();
@@ -4187,6 +4220,11 @@
}
}
+ if (requestToBeReleased != null) {
+ releaseNetworkRequestAndCallOnUnavailable(requestToBeReleased);
+ return;
+ }
+
if (mFlags.noRematchAllRequestsOnRegister()) {
rematchNetworksAndRequests(nris);
} else {
@@ -5026,6 +5064,11 @@
/* callOnUnavailable */ false);
break;
}
+ case EVENT_RELEASE_NETWORK_REQUEST_AND_CALL_UNAVAILABLE: {
+ handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1,
+ /* callOnUnavailable */ true);
+ break;
+ }
case EVENT_SET_ACCEPT_UNVALIDATED: {
Network network = (Network) msg.obj;
handleSetAcceptUnvalidated(network, toBool(msg.arg1), toBool(msg.arg2));
@@ -6330,12 +6373,24 @@
private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
String callingPackageName, String callingAttributionTag) {
if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) == false) {
- enforceConnectivityRestrictedNetworksPermission();
+ if (!networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
+ enforceConnectivityRestrictedNetworksPermission();
+ }
} else {
enforceChangePermission(callingPackageName, callingAttributionTag);
}
}
+ private boolean checkConnectivityRestrictedNetworksPermission(int callerPid, int callerUid) {
+ if (checkAnyPermissionOf(callerPid, callerUid,
+ android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS)
+ || checkAnyPermissionOf(callerPid, callerUid,
+ android.Manifest.permission.CONNECTIVITY_INTERNAL)) {
+ return true;
+ }
+ return false;
+ }
+
@Override
public boolean requestBandwidthUpdate(Network network) {
enforceAccessPermission();
@@ -6402,7 +6457,6 @@
ensureValidNetworkSpecifier(networkCapabilities);
restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities,
callingUid, callingPackageName);
-
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
@@ -6518,6 +6572,13 @@
EVENT_RELEASE_NETWORK_REQUEST, mDeps.getCallingUid(), 0, networkRequest));
}
+ private void releaseNetworkRequestAndCallOnUnavailable(NetworkRequest networkRequest) {
+ ensureNetworkRequestHasType(networkRequest);
+ mHandler.sendMessage(mHandler.obtainMessage(
+ EVENT_RELEASE_NETWORK_REQUEST_AND_CALL_UNAVAILABLE, mDeps.getCallingUid(), 0,
+ networkRequest));
+ }
+
private void handleRegisterNetworkProvider(NetworkProviderInfo npi) {
if (mNetworkProviderInfos.containsKey(npi.messenger)) {
// Avoid creating duplicates. even if an app makes a direct AIDL call.
diff --git a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
new file mode 100644
index 0000000..c5107ad
--- /dev/null
+++ b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2022 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.connectivity;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+
+import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.networkstack.apishim.TelephonyManagerShimImpl;
+import com.android.networkstack.apishim.common.TelephonyManagerShim;
+import com.android.networkstack.apishim.common.TelephonyManagerShim.CarrierPrivilegesListenerShim;
+import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * Tracks the uid of the carrier privileged app that provides the carrier config.
+ * Authenticates if the caller has same uid as
+ * carrier privileged app that provides the carrier config
+ * @hide
+ */
+public class CarrierPrivilegeAuthenticator extends BroadcastReceiver {
+ private static final String TAG = CarrierPrivilegeAuthenticator.class.getSimpleName();
+ private static final boolean DBG = true;
+
+ // The context is for the current user (system server)
+ private final Context mContext;
+ private final TelephonyManagerShim mTelephonyManagerShim;
+ private final TelephonyManager mTelephonyManager;
+ @GuardedBy("mLock")
+ private int[] mCarrierServiceUid;
+ @GuardedBy("mLock")
+ private int mModemCount = 0;
+ private final Object mLock = new Object();
+ private final HandlerThread mThread;
+ private final Handler mHandler;
+ @NonNull
+ private final List<CarrierPrivilegesListenerShim> mCarrierPrivilegesChangedListeners =
+ new ArrayList<>();
+
+ public CarrierPrivilegeAuthenticator(@NonNull final Context c,
+ @NonNull final TelephonyManager t,
+ @NonNull final TelephonyManagerShimImpl telephonyManagerShim) {
+ mContext = c;
+ mTelephonyManager = t;
+ mTelephonyManagerShim = telephonyManagerShim;
+ mThread = new HandlerThread(TAG);
+ mThread.start();
+ mHandler = new Handler(mThread.getLooper()) {};
+ synchronized (mLock) {
+ mModemCount = mTelephonyManager.getActiveModemCount();
+ registerForCarrierChanges();
+ updateCarrierServiceUid();
+ }
+ }
+
+ public CarrierPrivilegeAuthenticator(@NonNull final Context c,
+ @NonNull final TelephonyManager t) {
+ mContext = c;
+ mTelephonyManager = t;
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S) {
+ mTelephonyManagerShim = new TelephonyManagerShimImpl(mTelephonyManager);
+ } else {
+ mTelephonyManagerShim = null;
+ }
+ mThread = new HandlerThread(TAG);
+ mThread.start();
+ mHandler = new Handler(mThread.getLooper()) {};
+ synchronized (mLock) {
+ mModemCount = mTelephonyManager.getActiveModemCount();
+ registerForCarrierChanges();
+ updateCarrierServiceUid();
+ }
+ }
+
+ /**
+ * An adapter {@link Executor} that posts all executed tasks onto the given
+ * {@link Handler}.
+ *
+ * TODO : migrate to the version in frameworks/libs/net when it's ready
+ *
+ * @hide
+ */
+ public class HandlerExecutor implements Executor {
+ private final Handler mHandler;
+ public HandlerExecutor(@NonNull Handler handler) {
+ mHandler = handler;
+ }
+ @Override
+ public void execute(Runnable command) {
+ if (!mHandler.post(command)) {
+ throw new RejectedExecutionException(mHandler + " is shutting down");
+ }
+ }
+ }
+
+ /**
+ * Broadcast receiver for ACTION_MULTI_SIM_CONFIG_CHANGED
+ *
+ * <p>The broadcast receiver is registered with mHandler
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ switch (intent.getAction()) {
+ case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED:
+ handleActionMultiSimConfigChanged(context, intent);
+ break;
+ default:
+ Log.d(TAG, "Unknown intent received with action: " + intent.getAction());
+ }
+ }
+
+ private void handleActionMultiSimConfigChanged(Context context, Intent intent) {
+ unregisterCarrierPrivilegesListeners();
+ synchronized (mLock) {
+ mModemCount = mTelephonyManager.getActiveModemCount();
+ }
+ registerCarrierPrivilegesListeners();
+ updateCarrierServiceUid();
+ }
+
+ private void registerForCarrierChanges() {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
+ mContext.registerReceiver(this, filter, null, mHandler);
+ registerCarrierPrivilegesListeners();
+ }
+
+ private void registerCarrierPrivilegesListeners() {
+ final HandlerExecutor executor = new HandlerExecutor(mHandler);
+ int modemCount;
+ synchronized (mLock) {
+ modemCount = mModemCount;
+ }
+ try {
+ for (int i = 0; i < modemCount; i++) {
+ CarrierPrivilegesListenerShim carrierPrivilegesListener =
+ new CarrierPrivilegesListenerShim() {
+ @Override
+ public void onCarrierPrivilegesChanged(
+ @NonNull List<String> privilegedPackageNames,
+ @NonNull int[] privilegedUids) {
+ // Re-trigger the synchronous check (which is also very cheap due
+ // to caching in CarrierPrivilegesTracker). This allows consistency
+ // with the onSubscriptionsChangedListener and broadcasts.
+ updateCarrierServiceUid();
+ }
+ };
+ addCarrierPrivilegesListener(i, executor, carrierPrivilegesListener);
+ mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener);
+ }
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Encountered exception registering carrier privileges listeners", e);
+ }
+ }
+
+ private void addCarrierPrivilegesListener(int logicalSlotIndex, Executor executor,
+ CarrierPrivilegesListenerShim listener) {
+ if (mTelephonyManagerShim == null) {
+ return;
+ }
+ try {
+ mTelephonyManagerShim.addCarrierPrivilegesListener(
+ logicalSlotIndex, executor, listener);
+ } catch (UnsupportedApiLevelException unsupportedApiLevelException) {
+ Log.e(TAG, "addCarrierPrivilegesListener API is not available");
+ }
+ }
+
+ private void removeCarrierPrivilegesListener(CarrierPrivilegesListenerShim listener) {
+ if (mTelephonyManagerShim == null) {
+ return;
+ }
+ try {
+ mTelephonyManagerShim.removeCarrierPrivilegesListener(listener);
+ } catch (UnsupportedApiLevelException unsupportedApiLevelException) {
+ Log.e(TAG, "removeCarrierPrivilegesListener API is not available");
+ }
+ }
+
+ private String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) {
+ if (mTelephonyManagerShim == null) {
+ return null;
+ }
+ try {
+ return mTelephonyManagerShim.getCarrierServicePackageNameForLogicalSlot(
+ logicalSlotIndex);
+ } catch (UnsupportedApiLevelException unsupportedApiLevelException) {
+ Log.e(TAG, "getCarrierServicePackageNameForLogicalSlot API is not available");
+ }
+ return null;
+ }
+
+ private void unregisterCarrierPrivilegesListeners() {
+ for (CarrierPrivilegesListenerShim carrierPrivilegesListener :
+ mCarrierPrivilegesChangedListeners) {
+ removeCarrierPrivilegesListener(carrierPrivilegesListener);
+ }
+ mCarrierPrivilegesChangedListeners.clear();
+ }
+
+ /**
+ * Check if network request is allowed based upon carrrier service package.
+ *
+ * Network request for {@link NET_CAPABILITY_CBS} is allowed if the caller has
+ * carrier privilege and provides the carrier config. This function checks if caller
+ * has the same and returns true if it has else false.
+ *
+ * @param callingUid user identifier that uniquely identifies the caller.
+ * @param networkRequest the network request for which the carrier privilege is checked.
+ * @return true if caller has carrier privilege and provides the carrier config else false.
+ */
+ public boolean hasCarrierPrivilegeForNetworkRequest(int callingUid,
+ NetworkRequest networkRequest) {
+ if (callingUid != Process.INVALID_UID) {
+ final int subId = getSubIdFromNetworkSpecifier(
+ networkRequest.getNetworkSpecifier());
+ return callingUid == getCarrierServiceUidForSubId(subId);
+ }
+ return false;
+ }
+
+ @VisibleForTesting
+ void updateCarrierServiceUid() {
+ synchronized (mLock) {
+ mCarrierServiceUid = new int[mModemCount];
+ for (int i = 0; i < mModemCount; i++) {
+ mCarrierServiceUid[i] = getCarrierServicePackageUidForSlot(i);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ int getCarrierServiceUidForSubId(int subId) {
+ final int slotId = getSlotIndex(subId);
+ synchronized (mLock) {
+ if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX && slotId < mModemCount) {
+ return mCarrierServiceUid[slotId];
+ }
+ }
+ return Process.INVALID_UID;
+ }
+
+ @VisibleForTesting
+ protected int getSlotIndex(int subId) {
+ return SubscriptionManager.getSlotIndex(subId);
+ }
+
+ @VisibleForTesting
+ int getSubIdFromNetworkSpecifier(NetworkSpecifier specifier) {
+ if (specifier instanceof TelephonyNetworkSpecifier) {
+ return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
+ }
+ return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+ }
+
+ @VisibleForTesting
+ int getUidForPackage(String pkgName) {
+ if (pkgName == null) {
+ return Process.INVALID_UID;
+ }
+ try {
+ PackageManager pm = mContext.getPackageManager();
+ if (pm != null) {
+ ApplicationInfo applicationInfo = pm.getApplicationInfo(pkgName, 0);
+ if (applicationInfo != null) {
+ return applicationInfo.uid;
+ }
+ }
+ } catch (PackageManager.NameNotFoundException exception) {
+ // Didn't find package. Try other users
+ Log.i(TAG, "Unable to find uid for package " + pkgName);
+ }
+ return Process.INVALID_UID;
+ }
+
+ @VisibleForTesting
+ int getCarrierServicePackageUidForSlot(int slotId) {
+ return getUidForPackage(getCarrierServicePackageNameForLogicalSlot(slotId));
+ }
+}
diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp
index f66231d..e979a3b 100644
--- a/tests/cts/net/Android.bp
+++ b/tests/cts/net/Android.bp
@@ -70,7 +70,7 @@
// devices.
android_test {
name: "CtsNetTestCases",
- defaults: ["CtsNetTestCasesDefaults", "NetworkStackNextEnableDefaults"],
+ defaults: ["CtsNetTestCasesDefaults", "ConnectivityNextEnableDefaults"],
// TODO: CTS should not depend on the entirety of the networkstack code.
static_libs: [
"NetworkStackApiCurrentLib",
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index 9307c27..23814c9 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -62,7 +62,7 @@
class NsdManagerTest {
private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
private val nsdManager by lazy { context.getSystemService(NsdManager::class.java) }
- private val serviceName = "NsdTest%04d".format(Random().nextInt(1000))
+ private val serviceName = "NsdTest%09d".format(Random().nextInt(1_000_000_000))
private interface NsdEvent
private open class NsdRecord<T : NsdEvent> private constructor(
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 652aee9..8f67e48 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -5727,6 +5727,22 @@
}
}
+ /**
+ * Validate the callback flow CBS request without carrier privilege.
+ */
+ @Test
+ public void testCBSRequestWithoutCarrierPrivilege() throws Exception {
+ final NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ TRANSPORT_CELLULAR).addCapability(NET_CAPABILITY_CBS).build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+
+ mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_DENIED);
+ // Now file the test request and expect it.
+ mCm.requestNetwork(nr, networkCallback);
+ networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }
diff --git a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
new file mode 100644
index 0000000..d193aa9
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2022 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.connectivity;
+
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
+
+import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.net.NetworkRequest;
+import android.net.TelephonyNetworkSpecifier;
+import android.telephony.TelephonyManager;
+
+import com.android.networkstack.apishim.TelephonyManagerShimImpl;
+import com.android.networkstack.apishim.common.TelephonyManagerShim;
+import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Tests for CarrierPrivilegeAuthenticatorTest.
+ *
+ * Build, install and run with:
+ * runtest frameworks-net -c com.android.server.connectivity.CarrierPrivilegeAuthenticatorTest
+ */
+@RunWith(DevSdkIgnoreRunner.class)
+@IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
+public class CarrierPrivilegeAuthenticatorTest {
+ private static final String PACKAGE_NAME =
+ CarrierPrivilegeAuthenticatorTest.class.getPackage().getName();
+ private static final int TEST_SIM_SLOT_INDEX = 0;
+ private static final int TEST_SUBSCRIPTION_ID_1 = 2;
+ private static final int TEST_SUBSCRIPTION_ID_2 = 3;
+
+ @NonNull private final Context mContext;
+ @NonNull private final TelephonyManager mTelephonyManager;
+ @NonNull private final TelephonyManagerShimImpl mTelephonyManagerShim;
+ @NonNull private final PackageManager mPackageManager;
+ @NonNull private CarrierPrivilegeAuthenticatorChild mCarrierPrivilegeAuthenticator;
+ private final int mCarrierConfigPkgUid = 12345;
+ private final String mTestPkg = "com.android.server.connectivity.test";
+
+ public class CarrierPrivilegeAuthenticatorChild extends CarrierPrivilegeAuthenticator {
+ CarrierPrivilegeAuthenticatorChild(@NonNull final Context c,
+ @NonNull final TelephonyManager t) {
+ super(c, t, mTelephonyManagerShim);
+ }
+ @Override
+ protected int getSlotIndex(int subId) {
+ return subId;
+ }
+ }
+
+ public CarrierPrivilegeAuthenticatorTest() {
+ mContext = mock(Context.class);
+ mTelephonyManager = mock(TelephonyManager.class);
+ mTelephonyManagerShim = mock(TelephonyManagerShimImpl.class);
+ mPackageManager = mock(PackageManager.class);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ doReturn(2).when(mTelephonyManager).getActiveModemCount();
+ doReturn(mTestPkg).when(mTelephonyManagerShim)
+ .getCarrierServicePackageNameForLogicalSlot(anyInt());
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = mCarrierConfigPkgUid;
+ doReturn(applicationInfo).when(mPackageManager)
+ .getApplicationInfo(eq(mTestPkg), anyInt());
+ mCarrierPrivilegeAuthenticator =
+ new CarrierPrivilegeAuthenticatorChild(mContext, mTelephonyManager);
+ }
+
+ private IntentFilter getIntentFilter() {
+ final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
+ verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
+ return captor.getValue();
+ }
+
+ private List<TelephonyManagerShim.CarrierPrivilegesListenerShim>
+ getCarrierPrivilegesListeners() {
+ final ArgumentCaptor<TelephonyManagerShim.CarrierPrivilegesListenerShim> captor =
+ ArgumentCaptor.forClass(TelephonyManagerShim.CarrierPrivilegesListenerShim.class);
+ try {
+ verify(mTelephonyManagerShim, atLeastOnce())
+ .addCarrierPrivilegesListener(anyInt(), any(), captor.capture());
+ } catch (UnsupportedApiLevelException e) {
+
+ }
+ return captor.getAllValues();
+ }
+
+ private Intent buildTestMultiSimConfigBroadcastIntent() {
+ final Intent intent = new Intent(ACTION_MULTI_SIM_CONFIG_CHANGED);
+ return intent;
+ }
+ @Test
+ public void testConstructor() throws Exception {
+ verify(mContext).registerReceiver(
+ eq(mCarrierPrivilegeAuthenticator),
+ any(IntentFilter.class),
+ any(),
+ any());
+ final IntentFilter filter = getIntentFilter();
+ assertEquals(1, filter.countActions());
+ assertTrue(filter.hasAction(ACTION_MULTI_SIM_CONFIG_CHANGED));
+
+ verify(mTelephonyManagerShim, times(2))
+ .addCarrierPrivilegesListener(anyInt(), any(), any());
+ verify(mTelephonyManagerShim)
+ .addCarrierPrivilegesListener(eq(0), any(), any());
+ verify(mTelephonyManagerShim)
+ .addCarrierPrivilegesListener(eq(1), any(), any());
+ assertEquals(2, getCarrierPrivilegesListeners().size());
+
+ final TelephonyNetworkSpecifier telephonyNetworkSpecifier =
+ new TelephonyNetworkSpecifier(0);
+ final NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
+ networkRequestBuilder.addTransportType(TRANSPORT_CELLULAR);
+ networkRequestBuilder.setNetworkSpecifier(telephonyNetworkSpecifier);
+
+ assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
+ mCarrierConfigPkgUid, networkRequestBuilder.build()));
+ assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
+ mCarrierConfigPkgUid + 1, networkRequestBuilder.build()));
+ }
+
+ @Test
+ public void testMultiSimConfigChanged() throws Exception {
+ doReturn(1).when(mTelephonyManager).getActiveModemCount();
+ final List<TelephonyManagerShim.CarrierPrivilegesListenerShim> carrierPrivilegesListeners =
+ getCarrierPrivilegesListeners();
+
+ mCarrierPrivilegeAuthenticator.onReceive(
+ mContext, buildTestMultiSimConfigBroadcastIntent());
+ for (TelephonyManagerShim.CarrierPrivilegesListenerShim carrierPrivilegesListener
+ : carrierPrivilegesListeners) {
+ verify(mTelephonyManagerShim)
+ .removeCarrierPrivilegesListener(eq(carrierPrivilegesListener));
+ }
+
+ // Expect a new CarrierPrivilegesListener to have been registered for slot 0, and none other
+ // (2 previously registered during startup, for slots 0 & 1)
+ verify(mTelephonyManagerShim, times(3))
+ .addCarrierPrivilegesListener(anyInt(), any(), any());
+ verify(mTelephonyManagerShim, times(2))
+ .addCarrierPrivilegesListener(eq(0), any(), any());
+
+ final TelephonyNetworkSpecifier telephonyNetworkSpecifier =
+ new TelephonyNetworkSpecifier(0);
+ final NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
+ networkRequestBuilder.addTransportType(TRANSPORT_CELLULAR);
+ networkRequestBuilder.setNetworkSpecifier(telephonyNetworkSpecifier);
+ assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
+ mCarrierConfigPkgUid, networkRequestBuilder.build()));
+ assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
+ mCarrierConfigPkgUid + 1, networkRequestBuilder.build()));
+ }
+
+ @Test
+ public void testOnCarrierPrivilegesChanged() throws Exception {
+ final TelephonyManagerShim.CarrierPrivilegesListenerShim listener =
+ getCarrierPrivilegesListeners().get(0);
+
+ final TelephonyNetworkSpecifier telephonyNetworkSpecifier =
+ new TelephonyNetworkSpecifier(0);
+ final NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
+ networkRequestBuilder.addTransportType(TRANSPORT_CELLULAR);
+ networkRequestBuilder.setNetworkSpecifier(telephonyNetworkSpecifier);
+
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = mCarrierConfigPkgUid + 1;
+ doReturn(applicationInfo).when(mPackageManager)
+ .getApplicationInfo(eq(mTestPkg), anyInt());
+ listener.onCarrierPrivilegesChanged(Collections.emptyList(), new int[] {});
+
+ assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
+ mCarrierConfigPkgUid, networkRequestBuilder.build()));
+ assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
+ mCarrierConfigPkgUid + 1, networkRequestBuilder.build()));
+ }
+}
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 45f033c..76c0c38 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -198,6 +198,7 @@
@Mock
private LocationPermissionChecker mLocationPermissionChecker;
private @Mock IBpfMap<U32, U8> mUidCounterSetMap;
+ private @Mock NetworkStatsService.TagStatsDeleter mTagStatsDeleter;
private NetworkStatsService mService;
private INetworkStatsSession mSession;
@@ -358,6 +359,11 @@
public IBpfMap<U32, U8> getUidCounterSetMap() {
return mUidCounterSetMap;
}
+
+ @Override
+ public NetworkStatsService.TagStatsDeleter getTagStatsDeleter() {
+ return mTagStatsDeleter;
+ }
};
}
@@ -696,8 +702,10 @@
final Intent intent = new Intent(ACTION_UID_REMOVED);
intent.putExtra(EXTRA_UID, UID_BLUE);
mServiceContext.sendBroadcast(intent);
+ verify(mTagStatsDeleter).deleteTagData(UID_BLUE);
intent.putExtra(EXTRA_UID, UID_RED);
mServiceContext.sendBroadcast(intent);
+ verify(mTagStatsDeleter).deleteTagData(UID_RED);
// existing uid and total should remain unchanged; but removed UID
// should be gone completely.