diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java index bf7fb042ed..e095afea52 100644 --- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java +++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java @@ -254,8 +254,8 @@ public class TetheringService extends Service { // If callerPkg's uid is not same as Binder.getCallingUid(), // checkAndNoteWriteSettingsOperation will return false and the operation will be // denied. - return Settings.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg, - false /* throwException */); + return mService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg, + false /* throwException */); } private boolean hasTetherAccessPermission() { @@ -266,6 +266,19 @@ public class TetheringService extends Service { } } + /** + * Check if the package is a allowed to write settings. This also accounts that such an access + * happened. + * + * @return {@code true} iff the package is allowed to write settings. + */ + @VisibleForTesting + boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, + @NonNull String callingPackage, boolean throwException) { + return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage, + throwException); + } + /** * An injection method for testing. */ diff --git a/Tethering/tests/unit/AndroidManifest.xml b/Tethering/tests/unit/AndroidManifest.xml index 31eaabff52..355342f643 100644 --- a/Tethering/tests/unit/AndroidManifest.xml +++ b/Tethering/tests/unit/AndroidManifest.xml @@ -16,9 +16,6 @@ - - - 0) mUiAutomation.adoptShellPermissionIdentity(permissions); + try { + when(mTethering.isTetheringSupported()).thenReturn(true); + test.runTetheringCall(new TestTetheringResult()); + } finally { + mUiAutomation.dropShellPermissionIdentity(); + } + } + + private void verifyNoMoreInteractionsForTethering() { + verifyNoMoreInteractions(mTethering); + verifyNoMoreInteractions(mITetheringEventCallback); + reset(mTethering, mITetheringEventCallback); + } + + private void runTether(final TestTetheringResult result) throws Exception { + when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); + mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + verify(mTethering).isTetheringSupported(); + verify(mTethering).tether(TEST_IFACE_NAME); + result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testTether() throws Exception { - when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + runAsNoPermission((result) -> { + mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runTether(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runTether(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runUnTether(final TestTetheringResult result) throws Exception { + when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); + mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); - verify(mTethering).tether(TEST_IFACE_NAME); - verifyNoMoreInteractions(mTethering); + verify(mTethering).untether(TEST_IFACE_NAME); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testUntether() throws Exception { - when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR); - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + runAsNoPermission((result) -> { + mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runUnTether(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runUnTether(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runSetUsbTethering(final TestTetheringResult result) throws Exception { + when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR); + mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); - verify(mTethering).untether(TEST_IFACE_NAME); - verifyNoMoreInteractions(mTethering); + verify(mTethering).setUsbTethering(true /* enable */); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testSetUsbTethering() throws Exception { - when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR); - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result); + runAsNoPermission((result) -> { + mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runSetUsbTethering(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runSetUsbTethering(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + + } + + private void runStartTethering(final TestTetheringResult result, + final TetheringRequestParcel request) throws Exception { + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); - verify(mTethering).setUsbTethering(true /* enable */); - verifyNoMoreInteractions(mTethering); - result.assertResult(TETHER_ERROR_NO_ERROR); + verify(mTethering).startTethering(eq(request), eq(result)); } @Test public void testStartTethering() throws Exception { - final TestTetheringResult result = new TestTetheringResult(); final TetheringRequestParcel request = new TetheringRequestParcel(); request.tetheringType = TETHERING_WIFI; - mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result); - verify(mTethering).isTetheringSupported(); - verify(mTethering).startTethering(eq(request), eq(result)); - verifyNoMoreInteractions(mTethering); + + runAsNoPermission((result) -> { + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runStartTethering(result, request); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runStartTethering(result, request); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); } @Test - public void testStopTethering() throws Exception { - final TestTetheringResult result = new TestTetheringResult(); + public void testStartTetheringWithExemptFromEntitlementCheck() throws Exception { + final TetheringRequestParcel request = new TetheringRequestParcel(); + request.tetheringType = TETHERING_WIFI; + request.exemptFromEntitlementCheck = true; + + runAsTetherPrivileged((result) -> { + runStartTethering(result, request); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runStopTethering(final TestTetheringResult result) throws Exception { mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); verify(mTethering).stopTethering(TETHERING_WIFI); - verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test - public void testRequestLatestTetheringEntitlementResult() throws Exception { - final ResultReceiver result = new ResultReceiver(null); + public void testStopTethering() throws Exception { + runAsNoPermission((result) -> { + mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runStopTethering(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runStopTethering(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runRequestLatestTetheringEntitlementResult() throws Exception { + final MyResultReceiver result = new MyResultReceiver(null); mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, true /* showEntitlementUi */, TEST_CALLER_PKG); verify(mTethering).isTetheringSupported(); verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI), eq(result), eq(true) /* showEntitlementUi */); + } + + @Test + public void testRequestLatestTetheringEntitlementResult() throws Exception { + // Run as no permission. + final MyResultReceiver result = new MyResultReceiver(null); + mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result, + true /* showEntitlementUi */, TEST_CALLER_PKG); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); verifyNoMoreInteractions(mTethering); + + runAsTetherPrivileged((none) -> { + runRequestLatestTetheringEntitlementResult(); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((none) -> { + runRequestLatestTetheringEntitlementResult(); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runRegisterTetheringEventCallback() throws Exception { + mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback, + TEST_CALLER_PKG); + verify(mTethering).registerTetheringEventCallback(eq(mITetheringEventCallback)); } @Test public void testRegisterTetheringEventCallback() throws Exception { - mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback, + runAsNoPermission((result) -> { + mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback, + TEST_CALLER_PKG); + verify(mITetheringEventCallback).onCallbackStopped( + TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((none) -> { + runRegisterTetheringEventCallback(); + verifyNoMoreInteractionsForTethering(); + }); + + runAsAccessNetworkState((none) -> { + runRegisterTetheringEventCallback(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runUnregisterTetheringEventCallback() throws Exception { + mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback, TEST_CALLER_PKG); - verify(mTethering).registerTetheringEventCallback(eq(mITetheringEventCallback)); - verifyNoMoreInteractions(mTethering); + verify(mTethering).unregisterTetheringEventCallback(eq(mITetheringEventCallback)); } @Test public void testUnregisterTetheringEventCallback() throws Exception { - mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback, - TEST_CALLER_PKG); - verify(mTethering).unregisterTetheringEventCallback( - eq(mITetheringEventCallback)); - verifyNoMoreInteractions(mTethering); + runAsNoPermission((result) -> { + mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback, + TEST_CALLER_PKG); + verify(mITetheringEventCallback).onCallbackStopped( + TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((none) -> { + runUnregisterTetheringEventCallback(); + verifyNoMoreInteractionsForTethering(); + }); + + runAsAccessNetworkState((none) -> { + runUnregisterTetheringEventCallback(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runStopAllTethering(final TestTetheringResult result) throws Exception { + mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, result); + verify(mTethering).isTetheringSupported(); + verify(mTethering).untetherAll(); + result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testStopAllTethering() throws Exception { - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, result); + runAsNoPermission((result) -> { + mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runStopAllTethering(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runStopAllTethering(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); + } + + private void runIsTetheringSupported(final TestTetheringResult result) throws Exception { + mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); - verify(mTethering).untetherAll(); - verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testIsTetheringSupported() throws Exception { - final TestTetheringResult result = new TestTetheringResult(); - mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, result); - verify(mTethering).isTetheringSupported(); - verifyNoMoreInteractions(mTethering); - result.assertResult(TETHER_ERROR_NO_ERROR); + runAsNoPermission((result) -> { + mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, result); + verify(mTethering).isTetherProvisioningRequired(); + result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION); + verifyNoMoreInteractionsForTethering(); + }); + + runAsTetherPrivileged((result) -> { + runIsTetheringSupported(result); + verifyNoMoreInteractionsForTethering(); + }); + + runAsWriteSettings((result) -> { + runIsTetheringSupported(result); + verify(mTethering).isTetherProvisioningRequired(); + verifyNoMoreInteractionsForTethering(); + }); } }