OSDN Git Service

Close tethering when UI entitlement fails
authormarkchien <markchien@google.com>
Tue, 26 Mar 2019 13:41:59 +0000 (21:41 +0800)
committermarkchien <markchien@google.com>
Thu, 28 Mar 2019 03:48:40 +0000 (11:48 +0800)
This is a alternative way for moving TetherService logic
into EntitlementManager[1]. Settings would close tethering
when silent entitlement check fail. To be consistent,
tethering should also be closed if UI entitlement check
fails.

[1] https://android-review.googlesource.com/c/platform/frameworks/base/+/928136

bug: 129330738
Test: -build, flash, boot,
      -atest EntitlementManagerTest
      -manual test with carrier SIM

Change-Id: Idfc35461b6359f3a624e78d49b6f73812db6d8ab

services/core/java/com/android/server/connectivity/Tethering.java
services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java

index 0b1a98e..9986809 100644 (file)
@@ -233,6 +233,10 @@ public class Tethering extends BaseNetworkObserver {
         // permission is changed according to entitlement check result.
         mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
                 TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED, systemProperties);
+        mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
+            mLog.log("OBSERVED UiEnitlementFailed");
+            stopTethering(downstream);
+        });
 
         mCarrierConfigChange = new VersionedBroadcastListener(
                 "CarrierConfigChangeListener", mContext, mHandler, filter,
index 5c45397..764a6eb 100644 (file)
@@ -109,6 +109,7 @@ public class EntitlementManager {
     private boolean mCellularUpstreamPermitted = true;
     private boolean mUsingCellularAsUpstream = false;
     private boolean mNeedReRunProvisioningUi = false;
+    private OnUiEntitlementFailedListener mListener;
 
     public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
             int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
@@ -129,6 +130,20 @@ public class EntitlementManager {
                 null, mHandler);
     }
 
+    public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) {
+        mListener = listener;
+    }
+
+    /** Callback fired when UI entitlement failed. */
+    public interface OnUiEntitlementFailedListener {
+        /**
+         * Ui entitlement check fails in |downstream|.
+         *
+         * @param downstream  tethering type from ConnectivityManager.TETHERING_{@code *}.
+         */
+        void onUiEntitlementFailed(int downstream);
+    }
+
     /**
      * Pass a new TetheringConfiguration instance each time when
      * Tethering#updateConfiguration() is called.
@@ -337,7 +352,9 @@ public class EntitlementManager {
      */
     protected void runSilentTetherProvisioning(int type) {
         if (DBG) Log.d(TAG, "runSilentTetherProvisioning: " + type);
-        ResultReceiver receiver = buildProxyReceiver(type, null);
+        // For silent provisioning, settings would stop tethering when entitlement fail.
+        ResultReceiver receiver = buildProxyReceiver(type,
+                false/* notifyFail */, null);
 
         Intent intent = new Intent();
         intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
@@ -358,7 +375,8 @@ public class EntitlementManager {
      */
     @VisibleForTesting
     protected void runUiTetherProvisioning(int type) {
-        ResultReceiver receiver = buildProxyReceiver(type, null);
+        ResultReceiver receiver = buildProxyReceiver(type,
+                true/* notifyFail */, null);
         runUiTetherProvisioning(type, receiver);
     }
 
@@ -555,12 +573,16 @@ public class EntitlementManager {
         }
     }
 
-    private ResultReceiver buildProxyReceiver(int type, final ResultReceiver receiver) {
+    private ResultReceiver buildProxyReceiver(int type, boolean notifyFail,
+            final ResultReceiver receiver) {
         ResultReceiver rr = new ResultReceiver(mHandler) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
                 int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
                 addDownstreamMapping(type, updatedCacheValue);
+                if (updatedCacheValue == TETHER_ERROR_PROVISION_FAILED && notifyFail) {
+                    mListener.onUiEntitlementFailed(type);
+                }
                 if (receiver != null) receiver.send(updatedCacheValue, null);
             }
         };
@@ -627,7 +649,7 @@ public class EntitlementManager {
         if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
             receiver.send(cacheValue, null);
         } else {
-            ResultReceiver proxy = buildProxyReceiver(downstream, receiver);
+            ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
             runUiTetherProvisioning(downstream, proxy);
         }
     }
index 9eab4be..d28ab70 100644 (file)
@@ -31,6 +31,8 @@ import static org.junit.Assert.fail;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
@@ -80,6 +82,7 @@ public final class EntitlementManagerTest {
     @Mock private MockableSystemProperties mSystemProperties;
     @Mock private Resources mResources;
     @Mock private SharedLog mLog;
+    @Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;
 
     // Like so many Android system APIs, these cannot be mocked because it is marked final.
     // We have to use the real versions.
@@ -109,7 +112,6 @@ public final class EntitlementManagerTest {
 
     public class WrappedEntitlementManager extends EntitlementManager {
         public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
-        public boolean everRunUiEntitlement = false;
         public int uiProvisionCount = 0;
         public int silentProvisionCount = 0;
 
@@ -118,20 +120,22 @@ public final class EntitlementManagerTest {
             super(ctx, target, log, what, systemProperties);
         }
 
-        @Override
-        protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
-            everRunUiEntitlement = true;
-            receiver.send(fakeEntitlementResult, null);
+        public void reset() {
+            fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+            uiProvisionCount = 0;
+            silentProvisionCount = 0;
         }
 
         @Override
-        protected void runUiTetherProvisioning(int type) {
+        protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
             uiProvisionCount++;
+            receiver.send(fakeEntitlementResult, null);
         }
 
         @Override
         protected void runSilentTetherProvisioning(int type) {
             silentProvisionCount++;
+            addDownstreamMapping(type, fakeEntitlementResult);
         }
     }
 
@@ -157,6 +161,7 @@ public final class EntitlementManagerTest {
         mSM = new TestStateMachine();
         mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE,
                 mSystemProperties);
+        mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
         mEnMgr.updateConfiguration(
                 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
     }
@@ -246,7 +251,6 @@ public final class EntitlementManagerTest {
         final CountDownLatch mCallbacklatch = new CountDownLatch(1);
         // 1. Entitlement check is not required.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         ResultReceiver receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -257,13 +261,13 @@ public final class EntitlementManagerTest {
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
 
         setupForRequiredProvisioning();
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                   INVALID_SUBSCRIPTION_ID));
         // 2. No cache value and don't need to run entitlement check.
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -274,10 +278,10 @@ public final class EntitlementManagerTest {
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 3. No cache value and ui entitlement check is needed.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -288,10 +292,10 @@ public final class EntitlementManagerTest {
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertTrue(mEnMgr.everRunUiEntitlement);
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 4. Cache value is TETHER_ERROR_PROVISION_FAILED and don't need to run entitlement check.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -302,10 +306,10 @@ public final class EntitlementManagerTest {
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 5. Cache value is TETHER_ERROR_PROVISION_FAILED and ui entitlement check is needed.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -316,10 +320,10 @@ public final class EntitlementManagerTest {
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertTrue(mEnMgr.everRunUiEntitlement);
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 6. Cache value is TETHER_ERROR_NO_ERROR.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -330,9 +334,9 @@ public final class EntitlementManagerTest {
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 7. Test get value for other downstream type.
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -343,7 +347,8 @@ public final class EntitlementManagerTest {
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_USB, receiver, false);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
     }
 
     void callbackTimeoutHelper(final CountDownLatch latch) throws Exception {
@@ -358,15 +363,15 @@ public final class EntitlementManagerTest {
         mEnMgr.notifyUpstream(true);
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                   INVALID_SUBSCRIPTION_ID));
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
         mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
         mLooper.dispatchAll();
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_NO_ERROR);
         assertTrue(mEnMgr.isCellularUpstreamPermitted());
     }
 
@@ -376,17 +381,17 @@ public final class EntitlementManagerTest {
         mEnMgr.notifyUpstream(true);
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                   INVALID_SUBSCRIPTION_ID));
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
         assertFalse(mEnMgr.isCellularUpstreamPermitted());
     }
 
@@ -396,14 +401,14 @@ public final class EntitlementManagerTest {
         mEnMgr.notifyUpstream(true);
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                   INVALID_SUBSCRIPTION_ID));
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_NO_ERROR);
         assertTrue(mEnMgr.isCellularUpstreamPermitted());
         mLooper.dispatchAll();
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
         mLooper.dispatchAll();
-        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
         assertTrue(mEnMgr.isCellularUpstreamPermitted());
         mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
         mLooper.dispatchAll();
@@ -417,48 +422,71 @@ public final class EntitlementManagerTest {
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                 INVALID_SUBSCRIPTION_ID));
         // 1. start ui provisioning, upstream is mobile
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.notifyUpstream(true);
         mLooper.dispatchAll();
         mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
         mLooper.dispatchAll();
-        assertTrue(mEnMgr.uiProvisionCount == 1);
-        assertTrue(mEnMgr.silentProvisionCount == 0);
-        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.reset();
         // 2. start no-ui provisioning
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false);
         mLooper.dispatchAll();
-        assertTrue(mEnMgr.silentProvisionCount == 1);
-        assertTrue(mEnMgr.uiProvisionCount == 1);
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(1, mEnMgr.silentProvisionCount);
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.reset();
         // 3. tear down mobile, then start ui provisioning
         mEnMgr.notifyUpstream(false);
         mLooper.dispatchAll();
         mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
         mLooper.dispatchAll();
-        assertTrue(mEnMgr.uiProvisionCount == 1);
-        assertTrue(mEnMgr.silentProvisionCount == 1);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        mEnMgr.reset();
         // 4. switch upstream back to mobile
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
         mEnMgr.notifyUpstream(true);
         mLooper.dispatchAll();
-        assertTrue(mEnMgr.uiProvisionCount == 2);
-        assertTrue(mEnMgr.silentProvisionCount == 1);
-        mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.reset();
         // 5. tear down mobile, then switch SIM
         mEnMgr.notifyUpstream(false);
         mLooper.dispatchAll();
         mEnMgr.reevaluateSimCardProvisioning();
-        assertTrue(mEnMgr.uiProvisionCount == 2);
-        assertTrue(mEnMgr.silentProvisionCount == 1);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        mEnMgr.reset();
         // 6. switch upstream back to mobile again
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
         mEnMgr.notifyUpstream(true);
         mLooper.dispatchAll();
-        assertTrue(mEnMgr.uiProvisionCount == 2);
-        assertTrue(mEnMgr.silentProvisionCount == 4);
-        mEnMgr.addDownstreamMapping(TETHERING_USB, TETHER_ERROR_PROVISION_FAILED);
-        mEnMgr.addDownstreamMapping(TETHERING_WIFI, TETHER_ERROR_PROVISION_FAILED);
-        mEnMgr.addDownstreamMapping(TETHERING_BLUETOOTH, TETHER_ERROR_PROVISION_FAILED);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(3, mEnMgr.silentProvisionCount);
+        mEnMgr.reset();
     }
 
+    @Test
+    public void testCallStopTetheringWhenUiProvisioningFail() {
+        setupForRequiredProvisioning();
+        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
+                INVALID_SUBSCRIPTION_ID));
+        verify(mEntitlementFailedListener, times(0)).onUiEntitlementFailed(TETHERING_WIFI);
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.notifyUpstream(true);
+        mLooper.dispatchAll();
+        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+        mLooper.dispatchAll();
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI);
+    }
+
+
     public class TestStateMachine extends StateMachine {
         public final ArrayList<Message> messages = new ArrayList<>();
         private final State