Merge changes I7fae1964,Ic7cc9e1d into main
* changes:
Add carrier-privileged app bypass for start/stopTethering
Fix CarrierConfigRule#setHoldCarrierPrivilege race
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index b92cf69..737041e 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -146,7 +146,7 @@
mTethering.setUsbTethering(enable, listener);
}
- private boolean isRequestAllowedForDeviceOwner(@NonNull TetheringRequest request) {
+ private boolean isRequestAllowedForDOOrCarrierApp(@NonNull TetheringRequest request) {
return request.getTetheringType() == TETHERING_WIFI
&& request.getSoftApConfiguration() != null;
}
@@ -159,10 +159,10 @@
request.setPackageName(callerPkg);
boolean onlyAllowPrivileged = request.isExemptFromEntitlementCheck()
|| request.getInterfaceName() != null;
- boolean isDeviceOwnerAllowed = mTethering.isTetheringWithSoftApConfigEnabled()
- && isRequestAllowedForDeviceOwner(request);
+ boolean isDOOrCarrierAppAllowed = mTethering.isTetheringWithSoftApConfigEnabled()
+ && isRequestAllowedForDOOrCarrierApp(request);
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, onlyAllowPrivileged,
- isDeviceOwnerAllowed, listener)) {
+ isDOOrCarrierAppAllowed, listener)) {
return;
}
mTethering.startTethering(request, callerPkg, listener);
@@ -191,10 +191,10 @@
if (listener == null) return;
request.setUid(getBinderCallingUid());
request.setPackageName(callerPkg);
- boolean isDeviceOwnerAllowed = mTethering.isTetheringWithSoftApConfigEnabled()
- && isRequestAllowedForDeviceOwner(request);
+ boolean isDOOrCarrierAppAllowed = mTethering.isTetheringWithSoftApConfigEnabled()
+ && isRequestAllowedForDOOrCarrierApp(request);
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag,
- false /* onlyAllowPrivileged */, isDeviceOwnerAllowed, listener)) {
+ false /* onlyAllowPrivileged */, isDOOrCarrierAppAllowed, listener)) {
return;
}
// Note: Whether tethering is actually stopped or not will depend on whether the request
@@ -274,9 +274,9 @@
@Override
public void isTetheringSupported(String callerPkg, String callingAttributionTag,
IIntResultListener listener) {
- boolean isDeviceOwnerAppAllowed = mTethering.isTetheringWithSoftApConfigEnabled();
+ boolean isDOOrCarrierAppAllowed = mTethering.isTetheringWithSoftApConfigEnabled();
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag,
- false /* onlyAllowPrivileged */, isDeviceOwnerAppAllowed, listener)) {
+ false /* onlyAllowPrivileged */, isDOOrCarrierAppAllowed, listener)) {
return;
}
try {
@@ -304,7 +304,7 @@
private boolean checkAndNotifyCommonError(final String callerPkg,
final String callingAttributionTag, final boolean onlyAllowPrivileged,
- final boolean isDeviceOwnerAppAllowed, final IIntResultListener listener) {
+ final boolean isDOOrCarrierAppAllowed, final IIntResultListener listener) {
try {
final int uid = getBinderCallingUid();
if (!checkPackageNameMatchesUid(uid, callerPkg)) {
@@ -313,7 +313,7 @@
return true;
}
if (!hasTetherChangePermission(uid, callerPkg, callingAttributionTag,
- onlyAllowPrivileged, isDeviceOwnerAppAllowed)) {
+ onlyAllowPrivileged, isDOOrCarrierAppAllowed)) {
listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
return true;
}
@@ -347,14 +347,18 @@
private boolean hasTetherChangePermission(final int uid, final String callerPkg,
final String callingAttributionTag, final boolean onlyAllowPrivileged,
- final boolean isDeviceOwnerAppAllowed) {
+ final boolean isDOOrCarrierAppAllowed) {
if (onlyAllowPrivileged && !hasNetworkStackPermission()
&& !hasNetworkSettingsPermission()) return false;
if (hasTetherPrivilegedPermission()) return true;
- // Allow DO apps to change tethering even if they don't have TETHER_PRIVILEGED.
- if (isDeviceOwnerAppAllowed && mService.isDeviceOwner(uid, callerPkg)) {
+ // Allow DO and carrier-privileged apps to change tethering even if they don't have
+ // TETHER_PRIVILEGED.
+ // TODO: Stop tethering if the app loses DO status or carrier-privileges.
+ if (isDOOrCarrierAppAllowed
+ && (mService.isDeviceOwner(uid, callerPkg)
+ || mService.isCarrierPrivileged(callerPkg))) {
return true;
}
@@ -436,6 +440,14 @@
}
/**
+ * Wrapper for {@link TetheringPermissionsUtils#isCarrierPrivileged(String)}, used for mocks.
+ */
+ @VisibleForTesting
+ boolean isCarrierPrivileged(final String callerPkg) {
+ return mTetheringPermissionsUtils.isCarrierPrivileged(callerPkg);
+ }
+
+ /**
* An injection method for testing.
*/
@VisibleForTesting
diff --git a/Tethering/src/com/android/networkstack/tethering/util/TetheringPermissionsUtils.java b/Tethering/src/com/android/networkstack/tethering/util/TetheringPermissionsUtils.java
index 944e861..603fa9c 100644
--- a/Tethering/src/com/android/networkstack/tethering/util/TetheringPermissionsUtils.java
+++ b/Tethering/src/com/android/networkstack/tethering/util/TetheringPermissionsUtils.java
@@ -19,7 +19,9 @@
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.UserHandle;
+import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -68,4 +70,20 @@
}
return devicePolicyManager;
}
+
+ /**
+ * Checks if the package name has carrier privileges.
+ */
+ public boolean isCarrierPrivileged(@NonNull final String packageName) {
+ TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
+ if (telephonyManager == null) return false;
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
index a8bd221..01d7198 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java
@@ -37,6 +37,7 @@
private final ArrayMap<String, Integer> mMockedPermissions = new ArrayMap<>();
private final ArrayMap<String, Integer> mMockedPackageUids = new ArrayMap<>();
private final Set<String> mMockedDeviceOwnerPackages = new ArraySet<>();
+ private final Set<String> mMockedCarrierPrivilegedPackages = new ArraySet<>();
private int mMockCallingUid;
@Override
@@ -83,6 +84,11 @@
return mMockedDeviceOwnerPackages.contains(callerPkg);
}
+ @Override
+ boolean isCarrierPrivileged(final String callerPkg) {
+ return mMockedCarrierPrivilegedPackages.contains(callerPkg);
+ }
+
public Tethering getTethering() {
return mTethering;
}
@@ -141,5 +147,19 @@
public void removeDeviceOwnerPackage(final String packageName) {
mMockedDeviceOwnerPackages.remove(packageName);
}
+
+ /**
+ * Add a mocked carrier privileges package
+ */
+ public void addCarrierPrivilegedPackage(final String packageName) {
+ mMockedCarrierPrivilegedPackages.add(packageName);
+ }
+
+ /**
+ * Remove a mocked carrier privileges package
+ */
+ public void removeCarrierPrivilegedPackage(final String packageName) {
+ mMockedCarrierPrivilegedPackages.remove(packageName);
+ }
}
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index 87163ef..b58fa14 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -90,6 +90,15 @@
private static final int TEST_CALLER_UID = 1234;
private static final String TEST_ATTRIBUTION_TAG = null;
private static final String TEST_WRONG_PACKAGE = "wrong.package";
+ private static final int NO_RESULT = -1;
+ private static final TetheringRequest USB_REQUEST =
+ new TetheringRequest.Builder(TETHERING_USB).build();
+ private static final TetheringRequest WIFI_REQUEST_NO_CONFIG =
+ new TetheringRequest.Builder(TETHERING_WIFI).build();
+ private static final TetheringRequest WIFI_REQUEST_WITH_CONFIG =
+ new TetheringRequest.Builder(TETHERING_WIFI)
+ .setSoftApConfiguration(new SoftApConfiguration.Builder().build())
+ .build();
@Mock private ITetheringEventCallback mITetheringEventCallback;
@Rule public ServiceTestRule mServiceTestRule;
private Tethering mTethering;
@@ -100,7 +109,7 @@
@Mock private AppOpsManager mAppOps;
private class TestTetheringResult extends IIntResultListener.Stub {
- private int mResult = -1; // Default value that does not match any result code.
+ private int mResult = NO_RESULT;
@Override
public void onResult(final int resultCode) {
mResult = resultCode;
@@ -115,7 +124,7 @@
MyResultReceiver(Handler handler) {
super(handler);
}
- private int mResult = -1; // Default value that does not match any result code.
+ private int mResult = NO_RESULT;
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
mResult = resultCode;
@@ -206,6 +215,21 @@
mMockConnector.removeDeviceOwnerPackage(TEST_CALLER_PKG);
}
+ private void runAsCarrierPrivileged(final TestTetheringCall test) throws Exception {
+ mMockConnector.addCarrierPrivilegedPackage(TEST_CALLER_PKG);
+ runTetheringCall(test, true /* isTetheringAllowed */,
+ true /* isTetheringWithSoftApConfigEnabled */, new String[0]);
+ mMockConnector.removeCarrierPrivilegedPackage(TEST_CALLER_PKG);
+ }
+
+ private void runAsCarrierPrivilegedWhenCarrierPrivilegeBypassNotEnabled(
+ final TestTetheringCall test) throws Exception {
+ mMockConnector.addCarrierPrivilegedPackage(TEST_CALLER_PKG);
+ runTetheringCall(test, true /* isTetheringAllowed */,
+ false /* isTetheringWithSoftApConfigEnabled */, new String[0]);
+ mMockConnector.removeCarrierPrivilegedPackage(TEST_CALLER_PKG);
+ }
+
private void runTetheringCall(final TestTetheringCall test, boolean isTetheringAllowed,
boolean isTetheringWithSoftApConfigEnabled, String... permissions) throws Exception {
// Allow the test to run even if ACCESS_NETWORK_STATE was granted at the APK level
@@ -381,125 +405,114 @@
});
}
- private void runStartTethering(final TestTetheringResult result,
- final TetheringRequestParcel request) throws Exception {
- mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
- result);
- verify(mTethering, atLeastOnce()).isTetheringWithSoftApConfigEnabled();
- verify(mTethering).isTetheringSupported();
- verify(mTethering).isTetheringAllowed();
- verify(mTethering).startTethering(
- eq(new TetheringRequest(request)), eq(TEST_CALLER_PKG), eq(result));
+ private void verifyStartTetheringRequestSucceeds(final TetheringRequest request,
+ final TestTetheringResult result) throws Exception {
+ mTetheringConnector.startTethering(request.getParcel(), TEST_CALLER_PKG,
+ TEST_ATTRIBUTION_TAG, result);
+ verify(mTethering).startTethering(eq(request), eq(TEST_CALLER_PKG), eq(result));
+ reset(mTethering);
+ result.assertResult(NO_RESULT);
+ }
+
+ private void verifyStartTetheringRequestFails(final TetheringRequest request,
+ final TestTetheringResult result, final int resultCode) throws Exception {
+ mTetheringConnector.startTethering(request.getParcel(), TEST_CALLER_PKG,
+ TEST_ATTRIBUTION_TAG, result);
+ verify(mTethering, never()).startTethering(any(), any(), any());
+ reset(mTethering);
+ result.assertResult(resultCode);
+ }
+
+ private void verifyStartTetheringRequestWithWrongPackageFails(final TetheringRequest request,
+ final TestTetheringResult result) throws Exception {
+ mTetheringConnector.startTethering(request.getParcel(), TEST_WRONG_PACKAGE,
+ TEST_ATTRIBUTION_TAG, result);
+ verify(mTethering, never()).startTethering(any(), any(), any());
+ reset(mTethering);
+ result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
}
@Test
public void testStartTethering() throws Exception {
- final TetheringRequestParcel request = new TetheringRequestParcel();
- request.tetheringType = TETHERING_WIFI;
-
runAsNoPermission((result) -> {
- mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
- result);
- verify(mTethering, atLeastOnce()).isTetheringWithSoftApConfigEnabled();
- result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- verifyNoMoreInteractionsForTethering();
- });
-
- // Not a Wifi request - Fail
- runAsDeviceOwner((result) -> {
- final TetheringRequestParcel notWifi = new TetheringRequestParcel();
- notWifi.tetheringType = TETHERING_USB;
- mTetheringConnector.startTethering(notWifi, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
- result);
- verify(mTethering, atLeastOnce()).isTetheringWithSoftApConfigEnabled();
- result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- verifyNoMoreInteractionsForTethering();
- });
-
- // Request has no SoftApConfiguration - Fail
- runAsDeviceOwner((result) -> {
- final TetheringRequestParcel noConfig = new TetheringRequestParcel();
- noConfig.tetheringType = TETHERING_WIFI;
- mTetheringConnector.startTethering(noConfig, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
- result);
- verify(mTethering, atLeastOnce()).isTetheringWithSoftApConfigEnabled();
- result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- verifyNoMoreInteractionsForTethering();
- });
-
- // Wifi request with SoftApConfiguration - Succeed
- runAsDeviceOwner((result) -> {
- final TetheringRequestParcel withConfig = new TetheringRequestParcel();
- withConfig.tetheringType = TETHERING_WIFI;
- withConfig.softApConfig = new SoftApConfiguration.Builder().build();
- mTetheringConnector.startTethering(withConfig, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
- result);
- verify(mTethering, atLeastOnce()).isTetheringWithSoftApConfigEnabled();
- verify(mTethering).isTetheringSupported();
- verify(mTethering).isTetheringAllowed();
- verify(mTethering).startTethering(any(), any(), any());
- result.assertResult(-1); // No result
- verifyNoMoreInteractionsForTethering();
- });
-
- runAsDeviceOwnerWhenDeviceOwnerBypassNotEnabled((result) -> {
- mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
- result);
- verify(mTethering, atLeastOnce()).isTetheringWithSoftApConfigEnabled();
- result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- verify(mTethering).isTetherProvisioningRequired();
- verifyNoMoreInteractionsForTethering();
+ verifyStartTetheringRequestFails(WIFI_REQUEST_NO_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
});
runAsTetherPrivileged((result) -> {
- mTetheringConnector.startTethering(request, TEST_WRONG_PACKAGE,
- TEST_ATTRIBUTION_TAG, result);
- verify(mTethering, atLeastOnce()).isTetheringWithSoftApConfigEnabled();
- verify(mTethering, never()).startTethering(
- eq(new TetheringRequest(request)), eq(TEST_WRONG_PACKAGE), eq(result));
- result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- verifyNoMoreInteractionsForTethering();
+ verifyStartTetheringRequestSucceeds(WIFI_REQUEST_NO_CONFIG, result);
});
runAsTetherPrivileged((result) -> {
- runStartTethering(result, request);
- verifyNoMoreInteractionsForTethering();
+ verifyStartTetheringRequestWithWrongPackageFails(WIFI_REQUEST_NO_CONFIG, result);
});
runAsWriteSettings((result) -> {
- mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
- result);
- verify(mTethering, atLeastOnce()).isTetheringWithSoftApConfigEnabled();
- result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- verifyNoMoreInteractionsForTethering();
+ verifyStartTetheringRequestFails(WIFI_REQUEST_NO_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
});
runAsWriteSettingsWhenWriteSettingsAllowed((result) -> {
- runStartTethering(result, request);
- verify(mTethering, atLeastOnce()).isTetheringWithSoftApConfigEnabled();
- verify(mTethering).isTetherProvisioningRequired();
- verifyNoMoreInteractionsForTethering();
+ verifyStartTetheringRequestSucceeds(WIFI_REQUEST_NO_CONFIG, result);
});
runAsTetheringDisallowed((result) -> {
- mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
- result);
- verify(mTethering, atLeastOnce()).isTetheringWithSoftApConfigEnabled();
- verify(mTethering).isTetheringSupported();
- verify(mTethering).isTetheringAllowed();
- result.assertResult(TETHER_ERROR_UNSUPPORTED);
- verifyNoMoreInteractionsForTethering();
+ verifyStartTetheringRequestFails(WIFI_REQUEST_NO_CONFIG, result,
+ TETHER_ERROR_UNSUPPORTED);
+ });
+
+ // Not wifi -> fail
+ runAsDeviceOwner((result) -> {
+ verifyStartTetheringRequestFails(USB_REQUEST, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ });
+
+ // No SoftApConfiguration -> fail
+ runAsDeviceOwner((result) -> {
+ verifyStartTetheringRequestFails(WIFI_REQUEST_NO_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ });
+
+ // With SoftApConfiguration -> success
+ runAsDeviceOwner((result) -> {
+ verifyStartTetheringRequestSucceeds(WIFI_REQUEST_WITH_CONFIG, result);
+ });
+
+ runAsDeviceOwnerWhenDeviceOwnerBypassNotEnabled((result) -> {
+ verifyStartTetheringRequestFails(WIFI_REQUEST_WITH_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ });
+
+ // Not wifi -> fail
+ runAsCarrierPrivileged((result) -> {
+ verifyStartTetheringRequestFails(USB_REQUEST, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ });
+
+ // No SoftApConfiguration -> fail
+ runAsCarrierPrivileged((result) -> {
+ verifyStartTetheringRequestFails(WIFI_REQUEST_NO_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ });
+
+ // With SoftApConfiguration -> success
+ runAsCarrierPrivileged((result) -> {
+ verifyStartTetheringRequestSucceeds(WIFI_REQUEST_WITH_CONFIG, result);
+ });
+
+ runAsCarrierPrivilegedWhenCarrierPrivilegeBypassNotEnabled((result) -> {
+ verifyStartTetheringRequestFails(WIFI_REQUEST_WITH_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
});
}
@Test
public void testStartTetheringWithInterfaceSucceeds() throws Exception {
- final TetheringRequestParcel request = new TetheringRequestParcel();
- request.tetheringType = TETHERING_VIRTUAL;
- request.interfaceName = "avf_tap_fixed";
-
+ final TetheringRequest request = new TetheringRequest.Builder(TETHERING_VIRTUAL)
+ .setInterfaceName("avf_tap_fixed")
+ .build();
runAsNetworkSettings((result) -> {
- runStartTethering(result, request);
+ verifyStartTetheringRequestSucceeds(request, result);
verifyNoMoreInteractionsForTethering();
});
}
@@ -599,84 +612,110 @@
});
}
- private void verifyHasPermissionForStopTetheringRequest(TetheringRequest request,
+ private void verifyStopTetheringRequestSucceeds(final TetheringRequest request,
final TestTetheringResult result) throws Exception {
mTetheringConnector.stopTetheringRequest(request, TEST_CALLER_PKG,
TEST_ATTRIBUTION_TAG, result);
verify(mTethering).stopTetheringRequest(any(), any());
- verify(mTethering).isTetheringSupported();
- verify(mTethering).isTetheringAllowed();
reset(mTethering);
+ result.assertResult(NO_RESULT);
}
- private void verifyDoesNotHavePermissionForStopTetheringRequest(TetheringRequest request,
- final TestTetheringResult result) throws Exception {
+ private void verifyStopTetheringRequestFails(final TetheringRequest request,
+ final TestTetheringResult result, int resultCode) throws Exception {
mTetheringConnector.stopTetheringRequest(request, TEST_CALLER_PKG,
TEST_ATTRIBUTION_TAG, result);
verify(mTethering, never()).stopTetheringRequest(any(), any());
+ reset(mTethering);
+ result.assertResult(resultCode);
+ }
+
+ private void verifyStopTetheringRequestWithWrongPackageFails(final TetheringRequest request,
+ final TestTetheringResult result) throws Exception {
+ mTetheringConnector.stopTetheringRequest(request, TEST_WRONG_PACKAGE,
+ TEST_ATTRIBUTION_TAG, result);
+ verify(mTethering, never()).stopTetheringRequest(any(), any());
+ reset(mTethering);
result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- reset(mTethering);
- }
-
- private void verifyStopTetheringRequestWithTetheringDisallowed(TetheringRequest request,
- final TestTetheringResult result) throws Exception {
- mTetheringConnector.stopTetheringRequest(request, TEST_CALLER_PKG,
- TEST_ATTRIBUTION_TAG, result);
- verify(mTethering, never()).stopTetheringRequest(any(), any());
- result.assertResult(TETHER_ERROR_UNSUPPORTED);
- reset(mTethering);
}
@Test
public void testStopTetheringRequest() throws Exception {
- TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
-
runAsNoPermission((result) -> {
- verifyDoesNotHavePermissionForStopTetheringRequest(request, result);
+ verifyStopTetheringRequestFails(WIFI_REQUEST_NO_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
});
runAsTetherPrivileged((result) -> {
- verifyHasPermissionForStopTetheringRequest(request, result);
+ verifyStopTetheringRequestSucceeds(WIFI_REQUEST_NO_CONFIG, result);
+ });
+
+ runAsTetherPrivileged((result) -> {
+ verifyStopTetheringRequestWithWrongPackageFails(WIFI_REQUEST_NO_CONFIG, result);
});
runAsWriteSettings((result) -> {
- verifyDoesNotHavePermissionForStopTetheringRequest(request, result);
+ verifyStopTetheringRequestFails(WIFI_REQUEST_NO_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
});
runAsWriteSettingsWhenWriteSettingsAllowed((result) -> {
- verifyHasPermissionForStopTetheringRequest(request, result);
+ // Note: This can't happen in practice since WRITE_SETTINGS is only allowed on V- and
+ // stopTetheringRequest is only allowed on B+, but we test here for completeness.
+ verifyStopTetheringRequestSucceeds(WIFI_REQUEST_NO_CONFIG, result);
});
runAsTetheringDisallowed((result) -> {
- verifyStopTetheringRequestWithTetheringDisallowed(request, result);
+ verifyStopTetheringRequestFails(WIFI_REQUEST_NO_CONFIG, result,
+ TETHER_ERROR_UNSUPPORTED);
});
runAsNetworkSettings((result) -> {
- verifyHasPermissionForStopTetheringRequest(request, result);
+ verifyStopTetheringRequestSucceeds(WIFI_REQUEST_NO_CONFIG, result);
});
// Not wifi -> fail
runAsDeviceOwner((result) -> {
- TetheringRequest notWifi = new TetheringRequest.Builder(TETHERING_USB).build();
- verifyDoesNotHavePermissionForStopTetheringRequest(notWifi, result);
+ verifyStopTetheringRequestFails(USB_REQUEST, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
});
- // No config -> fail
+ // No SoftApConfiguration -> fail
runAsDeviceOwner((result) -> {
- TetheringRequest noConfig = new TetheringRequest.Builder(TETHERING_WIFI).build();
- verifyDoesNotHavePermissionForStopTetheringRequest(noConfig, result);
+ verifyStopTetheringRequestFails(WIFI_REQUEST_NO_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
});
- // With config -> success
- TetheringRequest withConfig = new TetheringRequest.Builder(TETHERING_WIFI)
- .setSoftApConfiguration(new SoftApConfiguration.Builder().build())
- .build();
+ // With SoftApConfiguration -> success
runAsDeviceOwner((result) -> {
- verifyHasPermissionForStopTetheringRequest(withConfig, result);
+ verifyStopTetheringRequestSucceeds(WIFI_REQUEST_WITH_CONFIG, result);
});
runAsDeviceOwnerWhenDeviceOwnerBypassNotEnabled((result) -> {
- verifyDoesNotHavePermissionForStopTetheringRequest(withConfig, result);
+ verifyStopTetheringRequestFails(WIFI_REQUEST_WITH_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ });
+
+ // Not wifi -> fail
+ runAsCarrierPrivileged((result) -> {
+ verifyStopTetheringRequestFails(USB_REQUEST, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ });
+
+ // No SoftApConfiguration -> fail
+ runAsCarrierPrivileged((result) -> {
+ verifyStopTetheringRequestFails(WIFI_REQUEST_NO_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ });
+
+ // With SoftApConfiguration -> success
+ runAsCarrierPrivileged((result) -> {
+ verifyStopTetheringRequestSucceeds(WIFI_REQUEST_WITH_CONFIG, result);
+ });
+
+ runAsCarrierPrivilegedWhenCarrierPrivilegeBypassNotEnabled((result) -> {
+ verifyStopTetheringRequestFails(WIFI_REQUEST_WITH_CONFIG, result,
+ TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
});
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/util/TetheringPermissionsUtilsTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/util/TetheringPermissionsUtilsTest.java
index 57c3eca..2b70e39 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/util/TetheringPermissionsUtilsTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/util/TetheringPermissionsUtilsTest.java
@@ -67,4 +67,15 @@
when(mDevicePolicyManager.isDeviceOwnerApp(TEST_PACKAGE)).thenReturn(true);
assertThat(mTetheringPermissionsUtils.isDeviceOwner(TEST_UID, TEST_PACKAGE)).isTrue();
}
+
+ @Test
+ public void testHasCarrierPrivilege() {
+ when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(TEST_PACKAGE))
+ .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+ assertThat(mTetheringPermissionsUtils.isCarrierPrivileged(TEST_PACKAGE)).isFalse();
+
+ when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(TEST_PACKAGE))
+ .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
+ assertThat(mTetheringPermissionsUtils.isCarrierPrivileged(TEST_PACKAGE)).isTrue();
+ }
}
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt
index c9d2527..076398e 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt
@@ -40,6 +40,7 @@
import com.android.testutils.runAsShell
import com.android.testutils.tryTest
import java.security.MessageDigest
+import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import org.junit.rules.TestRule
@@ -204,6 +205,7 @@
}
return@tryTest
}
+ cv.close()
if (hold) {
addConfigOverrides(subId, PersistableBundle().also {
it.putStringArray(CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY,
@@ -212,6 +214,9 @@
} else {
cleanUpNow()
}
+ assertTrue(cv.block(CARRIER_CONFIG_CHANGE_TIMEOUT_MS),
+ "Timed out waiting for CarrierPrivilegesCallback")
+ assertEquals(cpb.hasPrivilege, hold, "Couldn't set carrier privilege")
} cleanup @JvmSerializableLambda {
runAsShell(READ_PRIVILEGED_PHONE_STATE) @JvmSerializableLambda {
tm.unregisterCarrierPrivilegesCallback(cpb)
diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
index abe628b..92d58e6 100644
--- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -36,6 +36,7 @@
import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
+import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_REQUEST;
import static android.net.cts.util.CtsTetheringUtils.isAnyIfaceMatch;
import static android.os.Process.INVALID_UID;
@@ -714,4 +715,185 @@
assertThrows(UnsupportedOperationException.class, () -> mTM.tether("iface"));
assertThrows(UnsupportedOperationException.class, () -> mTM.untether("iface"));
}
+
+ @Test
+ public void testCarrierPrivilegedIsTetheringSupported() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastB());
+ assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
+ int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
+ mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
+ final TestTetheringEventCallback tetherEventCallback =
+ mCtsTetheringUtils.registerTetheringEventCallback();
+ try {
+ tetherEventCallback.assumeWifiTetheringSupported(mContext);
+ tetherEventCallback.expectNoTetheringActive();
+
+ assertTrue(mTM.isTetheringSupported());
+ } finally {
+ mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
+ }
+ }
+
+ @Test
+ public void testCarrierPrivilegedStartTetheringNonWifiFails() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastB());
+ assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
+ int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
+ mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
+ final TestTetheringEventCallback tetherEventCallback =
+ mCtsTetheringUtils.registerTetheringEventCallback();
+ try {
+ tetherEventCallback.assumeWifiTetheringSupported(mContext);
+ tetherEventCallback.expectNoTetheringActive();
+ StartTetheringCallback callback = new StartTetheringCallback();
+ TetheringRequest request = new TetheringRequest.Builder(TETHERING_USB).build();
+
+ mTM.startTethering(request, Runnable::run, callback);
+
+ callback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ } finally {
+ mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
+ }
+ }
+
+ @Test
+ public void testCarrierPrivilegedStartTetheringWifiWithoutConfigFails() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastB());
+ assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
+ int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
+ mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
+ final TestTetheringEventCallback tetherEventCallback =
+ mCtsTetheringUtils.registerTetheringEventCallback();
+ try {
+ tetherEventCallback.assumeWifiTetheringSupported(mContext);
+ tetherEventCallback.expectNoTetheringActive();
+ StartTetheringCallback callback = new StartTetheringCallback();
+ TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
+
+ mTM.startTethering(request, Runnable::run, callback);
+
+ callback.expectTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ } finally {
+ mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
+ }
+ }
+
+ @Test
+ public void testCarrierPrivilegedStartTetheringWifiWithConfigSucceeds() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastB());
+ assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
+ int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
+ mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
+ final TestTetheringEventCallback tetherEventCallback =
+ mCtsTetheringUtils.registerTetheringEventCallback();
+ try {
+ tetherEventCallback.assumeWifiTetheringSupported(mContext);
+ tetherEventCallback.expectNoTetheringActive();
+ SoftApConfiguration softApConfig = createSoftApConfiguration("Carrier-privileged");
+
+ mCtsTetheringUtils.startWifiTetheringNoPermissions(tetherEventCallback, softApConfig);
+ } finally {
+ mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
+ }
+ }
+
+ @Test
+ public void testCarrierPrivilegedStopTetheringNonWifiFails() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastB());
+ assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
+ int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
+ mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
+ final TestTetheringEventCallback tetherEventCallback =
+ mCtsTetheringUtils.registerTetheringEventCallback();
+ try {
+ tetherEventCallback.assumeWifiTetheringSupported(mContext);
+ tetherEventCallback.expectNoTetheringActive();
+ TetheringRequest request = new TetheringRequest.Builder(TETHERING_USB).build();
+ CtsTetheringUtils.StopTetheringCallback
+ callback = new CtsTetheringUtils.StopTetheringCallback();
+
+ mTM.stopTethering(request, Runnable::run, callback);
+
+ callback.expectStopTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ } finally {
+ mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
+ }
+ }
+
+ @Test
+ public void testCarrierPrivilegedStopTetheringWifiWithoutConfigFails() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastB());
+ assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
+ int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
+ mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
+ final TestTetheringEventCallback tetherEventCallback =
+ mCtsTetheringUtils.registerTetheringEventCallback();
+ try {
+ tetherEventCallback.assumeWifiTetheringSupported(mContext);
+ tetherEventCallback.expectNoTetheringActive();
+ TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
+ CtsTetheringUtils.StopTetheringCallback
+ callback = new CtsTetheringUtils.StopTetheringCallback();
+
+ mTM.stopTethering(request, Runnable::run, callback);
+
+ callback.expectStopTetheringFailed(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ } finally {
+ mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
+ }
+ }
+
+ @Test
+ public void testCarrierPrivilegedStopTetheringWifiWithConfigButNoActiveRequestFails()
+ throws Exception {
+ assumeTrue(SdkLevel.isAtLeastB());
+ assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
+ int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
+ mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
+ final TestTetheringEventCallback tetherEventCallback =
+ mCtsTetheringUtils.registerTetheringEventCallback();
+ try {
+ tetherEventCallback.assumeWifiTetheringSupported(mContext);
+ tetherEventCallback.expectNoTetheringActive();
+ SoftApConfiguration softApConfig = createSoftApConfiguration("Carrier-privileged");
+ TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
+ .setSoftApConfiguration(softApConfig)
+ .build();
+ CtsTetheringUtils.StopTetheringCallback
+ callback = new CtsTetheringUtils.StopTetheringCallback();
+
+ mTM.stopTethering(request, Runnable::run, callback);
+
+ callback.expectStopTetheringFailed(TETHER_ERROR_UNKNOWN_REQUEST);
+ } finally {
+ mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
+ }
+ }
+
+ @Test
+ public void testCarrierPrivilegedStopTetheringWifiWithConfigSucceeds() throws Exception {
+ assumeTrue(SdkLevel.isAtLeastB());
+ assumeTrue(mPm.hasSystemFeature(FEATURE_TELEPHONY));
+ int defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
+ mCarrierConfigRule.acquireCarrierPrivilege(defaultSubId);
+ final TestTetheringEventCallback tetherEventCallback =
+ mCtsTetheringUtils.registerTetheringEventCallback();
+ try {
+ tetherEventCallback.assumeWifiTetheringSupported(mContext);
+ tetherEventCallback.expectNoTetheringActive();
+ SoftApConfiguration softApConfig = createSoftApConfiguration("Carrier-privileged");
+ mCtsTetheringUtils.startWifiTetheringNoPermissions(tetherEventCallback, softApConfig);
+ TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
+ .setSoftApConfiguration(softApConfig)
+ .build();
+ CtsTetheringUtils.StopTetheringCallback
+ callback = new CtsTetheringUtils.StopTetheringCallback();
+
+ mTM.stopTethering(request, Runnable::run, callback);
+
+ callback.verifyStopTetheringSucceeded();
+ } finally {
+ mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
+ }
+ }
}