Loading packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java +15 −2 Original line number Diff line number Diff line Loading @@ -254,7 +254,7 @@ 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, return mService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg, false /* throwException */); } Loading @@ -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. */ Loading packages/Tethering/tests/unit/AndroidManifest.xml +0 −3 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.networkstack.tethering.tests.unit"> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/> <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> <service Loading packages/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java +14 −0 Original line number Diff line number Diff line Loading @@ -15,13 +15,19 @@ */ package com.android.networkstack.tethering; import static android.Manifest.permission.WRITE_SETTINGS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static org.mockito.Mockito.mock; import android.content.Context; import android.content.Intent; import android.net.ITetheringConnector; import android.os.Binder; import android.os.IBinder; import androidx.annotation.NonNull; public class MockTetheringService extends TetheringService { private final Tethering mTethering = mock(Tethering.class); Loading @@ -35,6 +41,14 @@ public class MockTetheringService extends TetheringService { return mTethering; } @Override boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, @NonNull String callingPackage, boolean throwException) { // Test this does not verify the calling package / UID, as calling package could be shell // and not match the UID. return context.checkCallingOrSelfPermission(WRITE_SETTINGS) == PERMISSION_GRANTED; } public Tethering getTethering() { return mTethering; } Loading packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java +304 −35 Original line number Diff line number Diff line Loading @@ -16,20 +16,30 @@ package com.android.networkstack.tethering; import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.TETHER_PRIVILEGED; import static android.Manifest.permission.UPDATE_APP_OPS_STATS; import static android.Manifest.permission.WRITE_SETTINGS; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.UiAutomation; import android.content.Intent; import android.net.IIntResultListener; import android.net.ITetheringConnector; import android.net.ITetheringEventCallback; import android.net.TetheringRequestParcel; import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; import androidx.test.InstrumentationRegistry; Loading @@ -51,12 +61,13 @@ import org.mockito.MockitoAnnotations; @SmallTest public final class TetheringServiceTest { private static final String TEST_IFACE_NAME = "test_wlan0"; private static final String TEST_CALLER_PKG = "test_pkg"; private static final String TEST_CALLER_PKG = "com.android.shell"; @Mock private ITetheringEventCallback mITetheringEventCallback; @Rule public ServiceTestRule mServiceTestRule; private Tethering mTethering; private Intent mMockServiceIntent; private ITetheringConnector mTetheringConnector; private UiAutomation mUiAutomation; private class TestTetheringResult extends IIntResultListener.Stub { private int mResult = -1; // Default value that does not match any result code. Loading @@ -70,9 +81,26 @@ public final class TetheringServiceTest { } } private class MyResultReceiver extends ResultReceiver { MyResultReceiver(Handler handler) { super(handler); } private int mResult = -1; // Default value that does not match any result code. @Override protected void onReceiveResult(int resultCode, Bundle resultData) { mResult = resultCode; } public void assertResult(int expected) { assertEquals(expected, mResult); } } @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); mServiceTestRule = new ServiceTestRule(); mMockServiceIntent = new Intent( InstrumentationRegistry.getTargetContext(), Loading @@ -82,112 +110,353 @@ public final class TetheringServiceTest { mTetheringConnector = mockConnector.getTetheringConnector(); final MockTetheringService service = mockConnector.getService(); mTethering = service.getTethering(); when(mTethering.isTetheringSupported()).thenReturn(true); } @After public void tearDown() throws Exception { mServiceTestRule.unbindService(); mUiAutomation.dropShellPermissionIdentity(); } @Test public void testTether() throws Exception { private interface TestTetheringCall { void runTetheringCall(TestTetheringResult result) throws Exception; } private void runAsNoPermission(final TestTetheringCall test) throws Exception { runTetheringCall(test, new String[0]); } private void runAsTetherPrivileged(final TestTetheringCall test) throws Exception { runTetheringCall(test, TETHER_PRIVILEGED); } private void runAsAccessNetworkState(final TestTetheringCall test) throws Exception { runTetheringCall(test, ACCESS_NETWORK_STATE); } private void runAsWriteSettings(final TestTetheringCall test) throws Exception { runTetheringCall(test, WRITE_SETTINGS, UPDATE_APP_OPS_STATS); } private void runTetheringCall(final TestTetheringCall test, String... permissions) throws Exception { if (permissions.length > 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); final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); verify(mTethering).tether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testUntether() throws Exception { public void testTether() throws Exception { 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); final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); verify(mTethering).untether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testSetUsbTethering() throws Exception { public void testUntether() throws Exception { 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); final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); verify(mTethering).setUsbTethering(true /* enable */); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testSetUsbTethering() throws Exception { 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).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; runAsNoPermission((result) -> { mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); verify(mTethering).startTethering(eq(request), eq(result)); verifyNoMoreInteractions(mTethering); 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 { runAsNoPermission((result) -> { mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback, TEST_CALLER_PKG); verify(mTethering).registerTetheringEventCallback(eq(mITetheringEventCallback)); verifyNoMoreInteractions(mTethering); 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).unregisterTetheringEventCallback(eq(mITetheringEventCallback)); } @Test public void testUnregisterTetheringEventCallback() throws Exception { runAsNoPermission((result) -> { mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback, TEST_CALLER_PKG); verify(mTethering).unregisterTetheringEventCallback( eq(mITetheringEventCallback)); verifyNoMoreInteractions(mTethering); verify(mITetheringEventCallback).onCallbackStopped( TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION); verifyNoMoreInteractionsForTethering(); }); runAsTetherPrivileged((none) -> { runUnregisterTetheringEventCallback(); verifyNoMoreInteractionsForTethering(); }); runAsAccessNetworkState((none) -> { runUnregisterTetheringEventCallback(); verifyNoMoreInteractionsForTethering(); }); } @Test public void testStopAllTethering() throws Exception { final TestTetheringResult result = new TestTetheringResult(); private void runStopAllTethering(final TestTetheringResult result) throws Exception { mTetheringConnector.stopAllTethering(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(); public void testStopAllTethering() throws Exception { 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(); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testIsTetheringSupported() throws Exception { 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(); }); } } Loading
packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java +15 −2 Original line number Diff line number Diff line Loading @@ -254,7 +254,7 @@ 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, return mService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg, false /* throwException */); } Loading @@ -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. */ Loading
packages/Tethering/tests/unit/AndroidManifest.xml +0 −3 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.networkstack.tethering.tests.unit"> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/> <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> <service Loading
packages/Tethering/tests/unit/src/com/android/networkstack/tethering/MockTetheringService.java +14 −0 Original line number Diff line number Diff line Loading @@ -15,13 +15,19 @@ */ package com.android.networkstack.tethering; import static android.Manifest.permission.WRITE_SETTINGS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static org.mockito.Mockito.mock; import android.content.Context; import android.content.Intent; import android.net.ITetheringConnector; import android.os.Binder; import android.os.IBinder; import androidx.annotation.NonNull; public class MockTetheringService extends TetheringService { private final Tethering mTethering = mock(Tethering.class); Loading @@ -35,6 +41,14 @@ public class MockTetheringService extends TetheringService { return mTethering; } @Override boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid, @NonNull String callingPackage, boolean throwException) { // Test this does not verify the calling package / UID, as calling package could be shell // and not match the UID. return context.checkCallingOrSelfPermission(WRITE_SETTINGS) == PERMISSION_GRANTED; } public Tethering getTethering() { return mTethering; } Loading
packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java +304 −35 Original line number Diff line number Diff line Loading @@ -16,20 +16,30 @@ package com.android.networkstack.tethering; import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.TETHER_PRIVILEGED; import static android.Manifest.permission.UPDATE_APP_OPS_STATS; import static android.Manifest.permission.WRITE_SETTINGS; import static android.net.TetheringManager.TETHERING_WIFI; import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.UiAutomation; import android.content.Intent; import android.net.IIntResultListener; import android.net.ITetheringConnector; import android.net.ITetheringEventCallback; import android.net.TetheringRequestParcel; import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; import androidx.test.InstrumentationRegistry; Loading @@ -51,12 +61,13 @@ import org.mockito.MockitoAnnotations; @SmallTest public final class TetheringServiceTest { private static final String TEST_IFACE_NAME = "test_wlan0"; private static final String TEST_CALLER_PKG = "test_pkg"; private static final String TEST_CALLER_PKG = "com.android.shell"; @Mock private ITetheringEventCallback mITetheringEventCallback; @Rule public ServiceTestRule mServiceTestRule; private Tethering mTethering; private Intent mMockServiceIntent; private ITetheringConnector mTetheringConnector; private UiAutomation mUiAutomation; private class TestTetheringResult extends IIntResultListener.Stub { private int mResult = -1; // Default value that does not match any result code. Loading @@ -70,9 +81,26 @@ public final class TetheringServiceTest { } } private class MyResultReceiver extends ResultReceiver { MyResultReceiver(Handler handler) { super(handler); } private int mResult = -1; // Default value that does not match any result code. @Override protected void onReceiveResult(int resultCode, Bundle resultData) { mResult = resultCode; } public void assertResult(int expected) { assertEquals(expected, mResult); } } @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); mServiceTestRule = new ServiceTestRule(); mMockServiceIntent = new Intent( InstrumentationRegistry.getTargetContext(), Loading @@ -82,112 +110,353 @@ public final class TetheringServiceTest { mTetheringConnector = mockConnector.getTetheringConnector(); final MockTetheringService service = mockConnector.getService(); mTethering = service.getTethering(); when(mTethering.isTetheringSupported()).thenReturn(true); } @After public void tearDown() throws Exception { mServiceTestRule.unbindService(); mUiAutomation.dropShellPermissionIdentity(); } @Test public void testTether() throws Exception { private interface TestTetheringCall { void runTetheringCall(TestTetheringResult result) throws Exception; } private void runAsNoPermission(final TestTetheringCall test) throws Exception { runTetheringCall(test, new String[0]); } private void runAsTetherPrivileged(final TestTetheringCall test) throws Exception { runTetheringCall(test, TETHER_PRIVILEGED); } private void runAsAccessNetworkState(final TestTetheringCall test) throws Exception { runTetheringCall(test, ACCESS_NETWORK_STATE); } private void runAsWriteSettings(final TestTetheringCall test) throws Exception { runTetheringCall(test, WRITE_SETTINGS, UPDATE_APP_OPS_STATS); } private void runTetheringCall(final TestTetheringCall test, String... permissions) throws Exception { if (permissions.length > 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); final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); verify(mTethering).tether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testUntether() throws Exception { public void testTether() throws Exception { 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); final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); verify(mTethering).untether(TEST_IFACE_NAME); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testSetUsbTethering() throws Exception { public void testUntether() throws Exception { 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); final TestTetheringResult result = new TestTetheringResult(); mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); verify(mTethering).setUsbTethering(true /* enable */); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testSetUsbTethering() throws Exception { 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).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; runAsNoPermission((result) -> { mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result); verify(mTethering).isTetheringSupported(); verify(mTethering).startTethering(eq(request), eq(result)); verifyNoMoreInteractions(mTethering); 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 { runAsNoPermission((result) -> { mTetheringConnector.registerTetheringEventCallback(mITetheringEventCallback, TEST_CALLER_PKG); verify(mTethering).registerTetheringEventCallback(eq(mITetheringEventCallback)); verifyNoMoreInteractions(mTethering); 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).unregisterTetheringEventCallback(eq(mITetheringEventCallback)); } @Test public void testUnregisterTetheringEventCallback() throws Exception { runAsNoPermission((result) -> { mTetheringConnector.unregisterTetheringEventCallback(mITetheringEventCallback, TEST_CALLER_PKG); verify(mTethering).unregisterTetheringEventCallback( eq(mITetheringEventCallback)); verifyNoMoreInteractions(mTethering); verify(mITetheringEventCallback).onCallbackStopped( TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION); verifyNoMoreInteractionsForTethering(); }); runAsTetherPrivileged((none) -> { runUnregisterTetheringEventCallback(); verifyNoMoreInteractionsForTethering(); }); runAsAccessNetworkState((none) -> { runUnregisterTetheringEventCallback(); verifyNoMoreInteractionsForTethering(); }); } @Test public void testStopAllTethering() throws Exception { final TestTetheringResult result = new TestTetheringResult(); private void runStopAllTethering(final TestTetheringResult result) throws Exception { mTetheringConnector.stopAllTethering(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(); public void testStopAllTethering() throws Exception { 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(); verifyNoMoreInteractions(mTethering); result.assertResult(TETHER_ERROR_NO_ERROR); } @Test public void testIsTetheringSupported() throws Exception { 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(); }); } }