Loading packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java +33 −27 Original line number Original line Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.IntentFilter; import android.net.util.SharedLog; import android.net.util.SharedLog; import android.os.Bundle; import android.os.Bundle; import android.os.ConditionVariable; import android.os.Handler; import android.os.Handler; import android.os.Parcel; import android.os.Parcel; import android.os.PersistableBundle; import android.os.PersistableBundle; Loading @@ -48,7 +49,6 @@ import android.telephony.CarrierConfigManager; import android.util.SparseIntArray; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.StateMachine; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.BitSet; import java.util.BitSet; Loading @@ -73,6 +73,7 @@ public class EntitlementManager { private final ComponentName mSilentProvisioningService; private final ComponentName mSilentProvisioningService; private static final int MS_PER_HOUR = 60 * 60 * 1000; private static final int MS_PER_HOUR = 60 * 60 * 1000; private static final int DUMP_TIMEOUT = 10_000; // The BitSet is the bit map of each enabled downstream types, ex: // The BitSet is the bit map of each enabled downstream types, ex: // {@link TetheringManager.TETHERING_WIFI} // {@link TetheringManager.TETHERING_WIFI} Loading @@ -80,14 +81,13 @@ public class EntitlementManager { // {@link TetheringManager.TETHERING_BLUETOOTH} // {@link TetheringManager.TETHERING_BLUETOOTH} private final BitSet mCurrentDownstreams; private final BitSet mCurrentDownstreams; private final Context mContext; private final Context mContext; private final int mPermissionChangeMessageCode; private final SharedLog mLog; private final SharedLog mLog; private final SparseIntArray mEntitlementCacheValue; private final SparseIntArray mEntitlementCacheValue; private final Handler mHandler; private final Handler mHandler; private final StateMachine mTetherMasterSM; // Key: TetheringManager.TETHERING_*(downstream). // Key: TetheringManager.TETHERING_*(downstream). // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). private final SparseIntArray mCurrentEntitlementResults; private final SparseIntArray mCurrentEntitlementResults; private final Runnable mPermissionChangeCallback; private PendingIntent mProvisioningRecheckAlarm; private PendingIntent mProvisioningRecheckAlarm; private boolean mLastCellularUpstreamPermitted = true; private boolean mLastCellularUpstreamPermitted = true; private boolean mUsingCellularAsUpstream = false; private boolean mUsingCellularAsUpstream = false; Loading @@ -95,16 +95,15 @@ public class EntitlementManager { private OnUiEntitlementFailedListener mListener; private OnUiEntitlementFailedListener mListener; private TetheringConfigurationFetcher mFetcher; private TetheringConfigurationFetcher mFetcher; public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log, public EntitlementManager(Context ctx, Handler h, SharedLog log, int permissionChangeMessageCode) { Runnable callback) { mContext = ctx; mContext = ctx; mLog = log.forSubComponent(TAG); mLog = log.forSubComponent(TAG); mCurrentDownstreams = new BitSet(); mCurrentDownstreams = new BitSet(); mCurrentEntitlementResults = new SparseIntArray(); mCurrentEntitlementResults = new SparseIntArray(); mEntitlementCacheValue = new SparseIntArray(); mEntitlementCacheValue = new SparseIntArray(); mTetherMasterSM = tetherMasterSM; mPermissionChangeCallback = callback; mPermissionChangeMessageCode = permissionChangeMessageCode; mHandler = h; mHandler = tetherMasterSM.getHandler(); mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM), mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM), null, mHandler); null, mHandler); mSilentProvisioningService = ComponentName.unflattenFromString( mSilentProvisioningService = ComponentName.unflattenFromString( Loading Loading @@ -409,25 +408,25 @@ public class EntitlementManager { } } private void evaluateCellularPermission(final TetheringConfiguration config) { private void evaluateCellularPermission(final TetheringConfiguration config) { final boolean oldPermitted = mLastCellularUpstreamPermitted; final boolean permitted = isCellularUpstreamPermitted(config); mLastCellularUpstreamPermitted = isCellularUpstreamPermitted(config); if (DBG) { if (DBG) { mLog.i("Cellular permission change from " + oldPermitted mLog.i("Cellular permission change from " + mLastCellularUpstreamPermitted + " to " + mLastCellularUpstreamPermitted); + " to " + permitted); } } if (mLastCellularUpstreamPermitted != oldPermitted) { if (mLastCellularUpstreamPermitted != permitted) { mLog.log("Cellular permission change: " + mLastCellularUpstreamPermitted); mLog.log("Cellular permission change: " + permitted); mTetherMasterSM.sendMessage(mPermissionChangeMessageCode); mPermissionChangeCallback.run(); } } // Only schedule periodic re-check when tether is provisioned // Only schedule periodic re-check when tether is provisioned // and the result is ok. // and the result is ok. if (mLastCellularUpstreamPermitted && mCurrentEntitlementResults.size() > 0) { if (permitted && mCurrentEntitlementResults.size() > 0) { scheduleProvisioningRechecks(config); scheduleProvisioningRechecks(config); } else { } else { cancelTetherProvisioningRechecks(); cancelTetherProvisioningRechecks(); } } mLastCellularUpstreamPermitted = permitted; } } /** /** Loading Loading @@ -486,6 +485,8 @@ public class EntitlementManager { * @param pw {@link PrintWriter} is used to print formatted * @param pw {@link PrintWriter} is used to print formatted */ */ public void dump(PrintWriter pw) { public void dump(PrintWriter pw) { final ConditionVariable mWaiting = new ConditionVariable(); mHandler.post(() -> { pw.print("isCellularUpstreamPermitted: "); pw.print("isCellularUpstreamPermitted: "); pw.println(isCellularUpstreamPermitted()); pw.println(isCellularUpstreamPermitted()); for (int type = mCurrentDownstreams.nextSetBit(0); type >= 0; for (int type = mCurrentDownstreams.nextSetBit(0); type >= 0; Loading @@ -499,6 +500,11 @@ public class EntitlementManager { pw.println(", Value: empty"); pw.println(", Value: empty"); } } } } mWaiting.open(); }); if (!mWaiting.block(DUMP_TIMEOUT)) { pw.println("... dump timed out after " + DUMP_TIMEOUT + "ms"); } } } private static String typeString(int type) { private static String typeString(int type) { Loading packages/Tethering/src/com/android/networkstack/tethering/Tethering.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -284,8 +284,9 @@ public class Tethering { filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream // permission is changed according to entitlement check result. // permission is changed according to entitlement check result. mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog, mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog, TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED); () -> mTetherMasterSM.sendMessage( TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED)); mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> { mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> { mLog.log("OBSERVED UiEnitlementFailed"); mLog.log("OBSERVED UiEnitlementFailed"); stopTethering(downstream); stopTethering(downstream); Loading packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +3 −3 Original line number Original line Diff line number Diff line Loading @@ -96,9 +96,9 @@ public abstract class TetheringDependencies { /** /** * Get a reference to the EntitlementManager to be used by tethering. * Get a reference to the EntitlementManager to be used by tethering. */ */ public EntitlementManager getEntitlementManager(Context ctx, StateMachine target, public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log, SharedLog log, int what) { Runnable callback) { return new EntitlementManager(ctx, target, log, what); return new EntitlementManager(ctx, h, log, callback); } } /** /** Loading packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java +70 −46 Original line number Original line Diff line number Diff line Loading @@ -37,6 +37,8 @@ import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.when; Loading @@ -45,7 +47,7 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.Resources; import android.net.util.SharedLog; import android.net.util.SharedLog; import android.os.Bundle; import android.os.Bundle; import android.os.Message; import android.os.Handler; import android.os.PersistableBundle; import android.os.PersistableBundle; import android.os.ResultReceiver; import android.os.ResultReceiver; import android.os.SystemProperties; import android.os.SystemProperties; Loading @@ -56,26 +58,22 @@ import android.telephony.CarrierConfigManager; import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.BroadcastInterceptingContext; import org.junit.After; import org.junit.After; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.RunWith; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; import org.mockito.quality.Strictness; import java.util.ArrayList; @RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class) @SmallTest @SmallTest public final class EntitlementManagerTest { public final class EntitlementManagerTest { private static final int EVENT_EM_UPDATE = 1; private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; Loading @@ -90,8 +88,8 @@ public final class EntitlementManagerTest { private final PersistableBundle mCarrierConfig = new PersistableBundle(); private final PersistableBundle mCarrierConfig = new PersistableBundle(); private final TestLooper mLooper = new TestLooper(); private final TestLooper mLooper = new TestLooper(); private Context mMockContext; private Context mMockContext; private Runnable mPermissionChangeCallback; private TestStateMachine mSM; private WrappedEntitlementManager mEnMgr; private WrappedEntitlementManager mEnMgr; private TetheringConfiguration mConfig; private TetheringConfiguration mConfig; private MockitoSession mMockingSession; private MockitoSession mMockingSession; Loading @@ -112,9 +110,9 @@ public final class EntitlementManagerTest { public int uiProvisionCount = 0; public int uiProvisionCount = 0; public int silentProvisionCount = 0; public int silentProvisionCount = 0; public WrappedEntitlementManager(Context ctx, StateMachine target, public WrappedEntitlementManager(Context ctx, Handler h, SharedLog log, SharedLog log, int what) { Runnable callback) { super(ctx, target, log, what); super(ctx, h, log, callback); } } public void reset() { public void reset() { Loading Loading @@ -169,8 +167,9 @@ public final class EntitlementManagerTest { when(mLog.forSubComponent(anyString())).thenReturn(mLog); when(mLog.forSubComponent(anyString())).thenReturn(mLog); mMockContext = new MockContext(mContext); mMockContext = new MockContext(mContext); mSM = new TestStateMachine(); mPermissionChangeCallback = spy(() -> { }); mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE); mEnMgr = new WrappedEntitlementManager(mMockContext, new Handler(mLooper.getLooper()), mLog, mPermissionChangeCallback); mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener); mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener); mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); mEnMgr.setTetheringConfigurationFetcher(() -> { mEnMgr.setTetheringConfigurationFetcher(() -> { Loading @@ -180,10 +179,6 @@ public final class EntitlementManagerTest { @After @After public void tearDown() throws Exception { public void tearDown() throws Exception { if (mSM != null) { mSM.quit(); mSM = null; } mMockingSession.finishMocking(); mMockingSession.finishMocking(); } } Loading Loading @@ -350,68 +345,105 @@ public final class EntitlementManagerTest { mEnMgr.reset(); mEnMgr.reset(); } } private void assertPermissionChangeCallback(InOrder inOrder) { inOrder.verify(mPermissionChangeCallback, times(1)).run(); } private void assertNoPermissionChange(InOrder inOrder) { inOrder.verifyNoMoreInteractions(); } @Test @Test public void verifyPermissionResult() { public void verifyPermissionResult() { final InOrder inOrder = inOrder(mPermissionChangeCallback); setupForRequiredProvisioning(); setupForRequiredProvisioning(); mEnMgr.notifyUpstream(true); mEnMgr.notifyUpstream(true); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: true -> false assertPermissionChangeCallback(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI); mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: false -> false assertNoPermissionChange(inOrder); mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: false -> true assertPermissionChangeCallback(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); } } @Test @Test public void verifyPermissionIfAllNotApproved() { public void verifyPermissionIfAllNotApproved() { final InOrder inOrder = inOrder(mPermissionChangeCallback); setupForRequiredProvisioning(); setupForRequiredProvisioning(); mEnMgr.notifyUpstream(true); mEnMgr.notifyUpstream(true); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: true -> false assertPermissionChangeCallback(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true); mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: false -> false assertNoPermissionChange(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true); mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: false -> false assertNoPermissionChange(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); } } @Test @Test public void verifyPermissionIfAnyApproved() { public void verifyPermissionIfAnyApproved() { final InOrder inOrder = inOrder(mPermissionChangeCallback); setupForRequiredProvisioning(); setupForRequiredProvisioning(); mEnMgr.notifyUpstream(true); mEnMgr.notifyUpstream(true); mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: true -> true assertNoPermissionChange(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mLooper.dispatchAll(); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true); mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: true -> true assertNoPermissionChange(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI); mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: true -> false assertPermissionChangeCallback(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); } } @Test @Test public void verifyPermissionWhenProvisioningNotStarted() { public void verifyPermissionWhenProvisioningNotStarted() { final InOrder inOrder = inOrder(mPermissionChangeCallback); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertNoPermissionChange(inOrder); setupForRequiredProvisioning(); setupForRequiredProvisioning(); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertNoPermissionChange(inOrder); } } @Test @Test public void testRunTetherProvisioning() { public void testRunTetherProvisioning() { final InOrder inOrder = inOrder(mPermissionChangeCallback); setupForRequiredProvisioning(); setupForRequiredProvisioning(); // 1. start ui provisioning, upstream is mobile // 1. start ui provisioning, upstream is mobile mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; Loading @@ -421,16 +453,22 @@ public final class EntitlementManagerTest { mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); // Permitted: true -> true assertNoPermissionChange(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.reset(); mEnMgr.reset(); // 2. start no-ui provisioning // 2. start no-ui provisioning mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false); mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(1, mEnMgr.silentProvisionCount); assertEquals(1, mEnMgr.silentProvisionCount); // Permitted: true -> true assertNoPermissionChange(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.reset(); mEnMgr.reset(); // 3. tear down mobile, then start ui provisioning // 3. tear down mobile, then start ui provisioning mEnMgr.notifyUpstream(false); mEnMgr.notifyUpstream(false); mLooper.dispatchAll(); mLooper.dispatchAll(); Loading @@ -438,44 +476,58 @@ public final class EntitlementManagerTest { mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertNoPermissionChange(inOrder); mEnMgr.reset(); mEnMgr.reset(); // 4. switch upstream back to mobile // 4. switch upstream back to mobile mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.notifyUpstream(true); mEnMgr.notifyUpstream(true); mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); // Permitted: true -> true assertNoPermissionChange(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.reset(); mEnMgr.reset(); // 5. tear down mobile, then switch SIM // 5. tear down mobile, then switch SIM mEnMgr.notifyUpstream(false); mEnMgr.notifyUpstream(false); mLooper.dispatchAll(); mLooper.dispatchAll(); mEnMgr.reevaluateSimCardProvisioning(mConfig); mEnMgr.reevaluateSimCardProvisioning(mConfig); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertNoPermissionChange(inOrder); mEnMgr.reset(); mEnMgr.reset(); // 6. switch upstream back to mobile again // 6. switch upstream back to mobile again mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.notifyUpstream(true); mEnMgr.notifyUpstream(true); mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(3, mEnMgr.silentProvisionCount); assertEquals(3, mEnMgr.silentProvisionCount); // Permitted: true -> false assertPermissionChangeCallback(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.reset(); mEnMgr.reset(); // 7. start ui provisioning, upstream is mobile, downstream is ethernet // 7. start ui provisioning, upstream is mobile, downstream is ethernet mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_ETHERNET, true); mEnMgr.startProvisioningIfNeeded(TETHERING_ETHERNET, true); mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); // Permitted: false -> true assertPermissionChangeCallback(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.reset(); mEnMgr.reset(); // 8. downstream is invalid // 8. downstream is invalid mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI_P2P, true); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI_P2P, true); mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertNoPermissionChange(inOrder); mEnMgr.reset(); mEnMgr.reset(); } } Loading @@ -491,32 +543,4 @@ public final class EntitlementManagerTest { assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(1, mEnMgr.uiProvisionCount); verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI); verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI); } } public class TestStateMachine extends StateMachine { public final ArrayList<Message> messages = new ArrayList<>(); private final State mLoggingState = new EntitlementManagerTest.TestStateMachine.LoggingState(); class LoggingState extends State { @Override public void enter() { messages.clear(); } @Override public void exit() { messages.clear(); } @Override public boolean processMessage(Message msg) { messages.add(msg); return false; } } public TestStateMachine() { super("EntitlementManagerTest.TestStateMachine", mLooper.getLooper()); addState(mLoggingState); setInitialState(mLoggingState); super.start(); } } } } packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +5 −3 Original line number Original line Diff line number Diff line Loading @@ -367,9 +367,9 @@ public class TetheringTest { } } @Override @Override public EntitlementManager getEntitlementManager(Context ctx, StateMachine target, public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log, SharedLog log, int what) { Runnable callback) { mEntitleMgr = spy(super.getEntitlementManager(ctx, target, log, what)); mEntitleMgr = spy(super.getEntitlementManager(ctx, h, log, callback)); return mEntitleMgr; return mEntitleMgr; } } Loading Loading @@ -1754,10 +1754,12 @@ public class TetheringTest { final FileDescriptor mockFd = mock(FileDescriptor.class); final FileDescriptor mockFd = mock(FileDescriptor.class); final PrintWriter mockPw = mock(PrintWriter.class); final PrintWriter mockPw = mock(PrintWriter.class); runUsbTethering(null); runUsbTethering(null); mLooper.startAutoDispatch(); mTethering.dump(mockFd, mockPw, new String[0]); mTethering.dump(mockFd, mockPw, new String[0]); verify(mConfig).dump(any()); verify(mConfig).dump(any()); verify(mEntitleMgr).dump(any()); verify(mEntitleMgr).dump(any()); verify(mOffloadCtrl).dump(any()); verify(mOffloadCtrl).dump(any()); mLooper.stopAutoDispatch(); } } // TODO: Test that a request for hotspot mode doesn't interfere with an // TODO: Test that a request for hotspot mode doesn't interfere with an Loading Loading
packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java +33 −27 Original line number Original line Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.IntentFilter; import android.net.util.SharedLog; import android.net.util.SharedLog; import android.os.Bundle; import android.os.Bundle; import android.os.ConditionVariable; import android.os.Handler; import android.os.Handler; import android.os.Parcel; import android.os.Parcel; import android.os.PersistableBundle; import android.os.PersistableBundle; Loading @@ -48,7 +49,6 @@ import android.telephony.CarrierConfigManager; import android.util.SparseIntArray; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.StateMachine; import java.io.PrintWriter; import java.io.PrintWriter; import java.util.BitSet; import java.util.BitSet; Loading @@ -73,6 +73,7 @@ public class EntitlementManager { private final ComponentName mSilentProvisioningService; private final ComponentName mSilentProvisioningService; private static final int MS_PER_HOUR = 60 * 60 * 1000; private static final int MS_PER_HOUR = 60 * 60 * 1000; private static final int DUMP_TIMEOUT = 10_000; // The BitSet is the bit map of each enabled downstream types, ex: // The BitSet is the bit map of each enabled downstream types, ex: // {@link TetheringManager.TETHERING_WIFI} // {@link TetheringManager.TETHERING_WIFI} Loading @@ -80,14 +81,13 @@ public class EntitlementManager { // {@link TetheringManager.TETHERING_BLUETOOTH} // {@link TetheringManager.TETHERING_BLUETOOTH} private final BitSet mCurrentDownstreams; private final BitSet mCurrentDownstreams; private final Context mContext; private final Context mContext; private final int mPermissionChangeMessageCode; private final SharedLog mLog; private final SharedLog mLog; private final SparseIntArray mEntitlementCacheValue; private final SparseIntArray mEntitlementCacheValue; private final Handler mHandler; private final Handler mHandler; private final StateMachine mTetherMasterSM; // Key: TetheringManager.TETHERING_*(downstream). // Key: TetheringManager.TETHERING_*(downstream). // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). private final SparseIntArray mCurrentEntitlementResults; private final SparseIntArray mCurrentEntitlementResults; private final Runnable mPermissionChangeCallback; private PendingIntent mProvisioningRecheckAlarm; private PendingIntent mProvisioningRecheckAlarm; private boolean mLastCellularUpstreamPermitted = true; private boolean mLastCellularUpstreamPermitted = true; private boolean mUsingCellularAsUpstream = false; private boolean mUsingCellularAsUpstream = false; Loading @@ -95,16 +95,15 @@ public class EntitlementManager { private OnUiEntitlementFailedListener mListener; private OnUiEntitlementFailedListener mListener; private TetheringConfigurationFetcher mFetcher; private TetheringConfigurationFetcher mFetcher; public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log, public EntitlementManager(Context ctx, Handler h, SharedLog log, int permissionChangeMessageCode) { Runnable callback) { mContext = ctx; mContext = ctx; mLog = log.forSubComponent(TAG); mLog = log.forSubComponent(TAG); mCurrentDownstreams = new BitSet(); mCurrentDownstreams = new BitSet(); mCurrentEntitlementResults = new SparseIntArray(); mCurrentEntitlementResults = new SparseIntArray(); mEntitlementCacheValue = new SparseIntArray(); mEntitlementCacheValue = new SparseIntArray(); mTetherMasterSM = tetherMasterSM; mPermissionChangeCallback = callback; mPermissionChangeMessageCode = permissionChangeMessageCode; mHandler = h; mHandler = tetherMasterSM.getHandler(); mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM), mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM), null, mHandler); null, mHandler); mSilentProvisioningService = ComponentName.unflattenFromString( mSilentProvisioningService = ComponentName.unflattenFromString( Loading Loading @@ -409,25 +408,25 @@ public class EntitlementManager { } } private void evaluateCellularPermission(final TetheringConfiguration config) { private void evaluateCellularPermission(final TetheringConfiguration config) { final boolean oldPermitted = mLastCellularUpstreamPermitted; final boolean permitted = isCellularUpstreamPermitted(config); mLastCellularUpstreamPermitted = isCellularUpstreamPermitted(config); if (DBG) { if (DBG) { mLog.i("Cellular permission change from " + oldPermitted mLog.i("Cellular permission change from " + mLastCellularUpstreamPermitted + " to " + mLastCellularUpstreamPermitted); + " to " + permitted); } } if (mLastCellularUpstreamPermitted != oldPermitted) { if (mLastCellularUpstreamPermitted != permitted) { mLog.log("Cellular permission change: " + mLastCellularUpstreamPermitted); mLog.log("Cellular permission change: " + permitted); mTetherMasterSM.sendMessage(mPermissionChangeMessageCode); mPermissionChangeCallback.run(); } } // Only schedule periodic re-check when tether is provisioned // Only schedule periodic re-check when tether is provisioned // and the result is ok. // and the result is ok. if (mLastCellularUpstreamPermitted && mCurrentEntitlementResults.size() > 0) { if (permitted && mCurrentEntitlementResults.size() > 0) { scheduleProvisioningRechecks(config); scheduleProvisioningRechecks(config); } else { } else { cancelTetherProvisioningRechecks(); cancelTetherProvisioningRechecks(); } } mLastCellularUpstreamPermitted = permitted; } } /** /** Loading Loading @@ -486,6 +485,8 @@ public class EntitlementManager { * @param pw {@link PrintWriter} is used to print formatted * @param pw {@link PrintWriter} is used to print formatted */ */ public void dump(PrintWriter pw) { public void dump(PrintWriter pw) { final ConditionVariable mWaiting = new ConditionVariable(); mHandler.post(() -> { pw.print("isCellularUpstreamPermitted: "); pw.print("isCellularUpstreamPermitted: "); pw.println(isCellularUpstreamPermitted()); pw.println(isCellularUpstreamPermitted()); for (int type = mCurrentDownstreams.nextSetBit(0); type >= 0; for (int type = mCurrentDownstreams.nextSetBit(0); type >= 0; Loading @@ -499,6 +500,11 @@ public class EntitlementManager { pw.println(", Value: empty"); pw.println(", Value: empty"); } } } } mWaiting.open(); }); if (!mWaiting.block(DUMP_TIMEOUT)) { pw.println("... dump timed out after " + DUMP_TIMEOUT + "ms"); } } } private static String typeString(int type) { private static String typeString(int type) { Loading
packages/Tethering/src/com/android/networkstack/tethering/Tethering.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -284,8 +284,9 @@ public class Tethering { filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream // permission is changed according to entitlement check result. // permission is changed according to entitlement check result. mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog, mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog, TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED); () -> mTetherMasterSM.sendMessage( TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED)); mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> { mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> { mLog.log("OBSERVED UiEnitlementFailed"); mLog.log("OBSERVED UiEnitlementFailed"); stopTethering(downstream); stopTethering(downstream); Loading
packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +3 −3 Original line number Original line Diff line number Diff line Loading @@ -96,9 +96,9 @@ public abstract class TetheringDependencies { /** /** * Get a reference to the EntitlementManager to be used by tethering. * Get a reference to the EntitlementManager to be used by tethering. */ */ public EntitlementManager getEntitlementManager(Context ctx, StateMachine target, public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log, SharedLog log, int what) { Runnable callback) { return new EntitlementManager(ctx, target, log, what); return new EntitlementManager(ctx, h, log, callback); } } /** /** Loading
packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java +70 −46 Original line number Original line Diff line number Diff line Loading @@ -37,6 +37,8 @@ import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.when; Loading @@ -45,7 +47,7 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.Resources; import android.net.util.SharedLog; import android.net.util.SharedLog; import android.os.Bundle; import android.os.Bundle; import android.os.Message; import android.os.Handler; import android.os.PersistableBundle; import android.os.PersistableBundle; import android.os.ResultReceiver; import android.os.ResultReceiver; import android.os.SystemProperties; import android.os.SystemProperties; Loading @@ -56,26 +58,22 @@ import android.telephony.CarrierConfigManager; import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.BroadcastInterceptingContext; import org.junit.After; import org.junit.After; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.RunWith; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations; import org.mockito.MockitoSession; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; import org.mockito.quality.Strictness; import java.util.ArrayList; @RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class) @SmallTest @SmallTest public final class EntitlementManagerTest { public final class EntitlementManagerTest { private static final int EVENT_EM_UPDATE = 1; private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; Loading @@ -90,8 +88,8 @@ public final class EntitlementManagerTest { private final PersistableBundle mCarrierConfig = new PersistableBundle(); private final PersistableBundle mCarrierConfig = new PersistableBundle(); private final TestLooper mLooper = new TestLooper(); private final TestLooper mLooper = new TestLooper(); private Context mMockContext; private Context mMockContext; private Runnable mPermissionChangeCallback; private TestStateMachine mSM; private WrappedEntitlementManager mEnMgr; private WrappedEntitlementManager mEnMgr; private TetheringConfiguration mConfig; private TetheringConfiguration mConfig; private MockitoSession mMockingSession; private MockitoSession mMockingSession; Loading @@ -112,9 +110,9 @@ public final class EntitlementManagerTest { public int uiProvisionCount = 0; public int uiProvisionCount = 0; public int silentProvisionCount = 0; public int silentProvisionCount = 0; public WrappedEntitlementManager(Context ctx, StateMachine target, public WrappedEntitlementManager(Context ctx, Handler h, SharedLog log, SharedLog log, int what) { Runnable callback) { super(ctx, target, log, what); super(ctx, h, log, callback); } } public void reset() { public void reset() { Loading Loading @@ -169,8 +167,9 @@ public final class EntitlementManagerTest { when(mLog.forSubComponent(anyString())).thenReturn(mLog); when(mLog.forSubComponent(anyString())).thenReturn(mLog); mMockContext = new MockContext(mContext); mMockContext = new MockContext(mContext); mSM = new TestStateMachine(); mPermissionChangeCallback = spy(() -> { }); mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE); mEnMgr = new WrappedEntitlementManager(mMockContext, new Handler(mLooper.getLooper()), mLog, mPermissionChangeCallback); mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener); mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener); mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); mEnMgr.setTetheringConfigurationFetcher(() -> { mEnMgr.setTetheringConfigurationFetcher(() -> { Loading @@ -180,10 +179,6 @@ public final class EntitlementManagerTest { @After @After public void tearDown() throws Exception { public void tearDown() throws Exception { if (mSM != null) { mSM.quit(); mSM = null; } mMockingSession.finishMocking(); mMockingSession.finishMocking(); } } Loading Loading @@ -350,68 +345,105 @@ public final class EntitlementManagerTest { mEnMgr.reset(); mEnMgr.reset(); } } private void assertPermissionChangeCallback(InOrder inOrder) { inOrder.verify(mPermissionChangeCallback, times(1)).run(); } private void assertNoPermissionChange(InOrder inOrder) { inOrder.verifyNoMoreInteractions(); } @Test @Test public void verifyPermissionResult() { public void verifyPermissionResult() { final InOrder inOrder = inOrder(mPermissionChangeCallback); setupForRequiredProvisioning(); setupForRequiredProvisioning(); mEnMgr.notifyUpstream(true); mEnMgr.notifyUpstream(true); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: true -> false assertPermissionChangeCallback(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI); mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: false -> false assertNoPermissionChange(inOrder); mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: false -> true assertPermissionChangeCallback(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); } } @Test @Test public void verifyPermissionIfAllNotApproved() { public void verifyPermissionIfAllNotApproved() { final InOrder inOrder = inOrder(mPermissionChangeCallback); setupForRequiredProvisioning(); setupForRequiredProvisioning(); mEnMgr.notifyUpstream(true); mEnMgr.notifyUpstream(true); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: true -> false assertPermissionChangeCallback(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true); mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: false -> false assertNoPermissionChange(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true); mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: false -> false assertNoPermissionChange(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); } } @Test @Test public void verifyPermissionIfAnyApproved() { public void verifyPermissionIfAnyApproved() { final InOrder inOrder = inOrder(mPermissionChangeCallback); setupForRequiredProvisioning(); setupForRequiredProvisioning(); mEnMgr.notifyUpstream(true); mEnMgr.notifyUpstream(true); mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: true -> true assertNoPermissionChange(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mLooper.dispatchAll(); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true); mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: true -> true assertNoPermissionChange(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI); mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI); mLooper.dispatchAll(); mLooper.dispatchAll(); // Permitted: true -> false assertPermissionChangeCallback(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); } } @Test @Test public void verifyPermissionWhenProvisioningNotStarted() { public void verifyPermissionWhenProvisioningNotStarted() { final InOrder inOrder = inOrder(mPermissionChangeCallback); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertNoPermissionChange(inOrder); setupForRequiredProvisioning(); setupForRequiredProvisioning(); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertNoPermissionChange(inOrder); } } @Test @Test public void testRunTetherProvisioning() { public void testRunTetherProvisioning() { final InOrder inOrder = inOrder(mPermissionChangeCallback); setupForRequiredProvisioning(); setupForRequiredProvisioning(); // 1. start ui provisioning, upstream is mobile // 1. start ui provisioning, upstream is mobile mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; Loading @@ -421,16 +453,22 @@ public final class EntitlementManagerTest { mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); // Permitted: true -> true assertNoPermissionChange(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.reset(); mEnMgr.reset(); // 2. start no-ui provisioning // 2. start no-ui provisioning mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false); mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(1, mEnMgr.silentProvisionCount); assertEquals(1, mEnMgr.silentProvisionCount); // Permitted: true -> true assertNoPermissionChange(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.reset(); mEnMgr.reset(); // 3. tear down mobile, then start ui provisioning // 3. tear down mobile, then start ui provisioning mEnMgr.notifyUpstream(false); mEnMgr.notifyUpstream(false); mLooper.dispatchAll(); mLooper.dispatchAll(); Loading @@ -438,44 +476,58 @@ public final class EntitlementManagerTest { mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertNoPermissionChange(inOrder); mEnMgr.reset(); mEnMgr.reset(); // 4. switch upstream back to mobile // 4. switch upstream back to mobile mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.notifyUpstream(true); mEnMgr.notifyUpstream(true); mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); // Permitted: true -> true assertNoPermissionChange(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.reset(); mEnMgr.reset(); // 5. tear down mobile, then switch SIM // 5. tear down mobile, then switch SIM mEnMgr.notifyUpstream(false); mEnMgr.notifyUpstream(false); mLooper.dispatchAll(); mLooper.dispatchAll(); mEnMgr.reevaluateSimCardProvisioning(mConfig); mEnMgr.reevaluateSimCardProvisioning(mConfig); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertNoPermissionChange(inOrder); mEnMgr.reset(); mEnMgr.reset(); // 6. switch upstream back to mobile again // 6. switch upstream back to mobile again mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED; mEnMgr.notifyUpstream(true); mEnMgr.notifyUpstream(true); mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(3, mEnMgr.silentProvisionCount); assertEquals(3, mEnMgr.silentProvisionCount); // Permitted: true -> false assertPermissionChangeCallback(inOrder); assertFalse(mEnMgr.isCellularUpstreamPermitted()); assertFalse(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.reset(); mEnMgr.reset(); // 7. start ui provisioning, upstream is mobile, downstream is ethernet // 7. start ui provisioning, upstream is mobile, downstream is ethernet mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_ETHERNET, true); mEnMgr.startProvisioningIfNeeded(TETHERING_ETHERNET, true); mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); // Permitted: false -> true assertPermissionChangeCallback(inOrder); assertTrue(mEnMgr.isCellularUpstreamPermitted()); assertTrue(mEnMgr.isCellularUpstreamPermitted()); mEnMgr.reset(); mEnMgr.reset(); // 8. downstream is invalid // 8. downstream is invalid mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI_P2P, true); mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI_P2P, true); mLooper.dispatchAll(); mLooper.dispatchAll(); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); assertNoPermissionChange(inOrder); mEnMgr.reset(); mEnMgr.reset(); } } Loading @@ -491,32 +543,4 @@ public final class EntitlementManagerTest { assertEquals(1, mEnMgr.uiProvisionCount); assertEquals(1, mEnMgr.uiProvisionCount); verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI); verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI); } } public class TestStateMachine extends StateMachine { public final ArrayList<Message> messages = new ArrayList<>(); private final State mLoggingState = new EntitlementManagerTest.TestStateMachine.LoggingState(); class LoggingState extends State { @Override public void enter() { messages.clear(); } @Override public void exit() { messages.clear(); } @Override public boolean processMessage(Message msg) { messages.add(msg); return false; } } public TestStateMachine() { super("EntitlementManagerTest.TestStateMachine", mLooper.getLooper()); addState(mLoggingState); setInitialState(mLoggingState); super.start(); } } } }
packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +5 −3 Original line number Original line Diff line number Diff line Loading @@ -367,9 +367,9 @@ public class TetheringTest { } } @Override @Override public EntitlementManager getEntitlementManager(Context ctx, StateMachine target, public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log, SharedLog log, int what) { Runnable callback) { mEntitleMgr = spy(super.getEntitlementManager(ctx, target, log, what)); mEntitleMgr = spy(super.getEntitlementManager(ctx, h, log, callback)); return mEntitleMgr; return mEntitleMgr; } } Loading Loading @@ -1754,10 +1754,12 @@ public class TetheringTest { final FileDescriptor mockFd = mock(FileDescriptor.class); final FileDescriptor mockFd = mock(FileDescriptor.class); final PrintWriter mockPw = mock(PrintWriter.class); final PrintWriter mockPw = mock(PrintWriter.class); runUsbTethering(null); runUsbTethering(null); mLooper.startAutoDispatch(); mTethering.dump(mockFd, mockPw, new String[0]); mTethering.dump(mockFd, mockPw, new String[0]); verify(mConfig).dump(any()); verify(mConfig).dump(any()); verify(mEntitleMgr).dump(any()); verify(mEntitleMgr).dump(any()); verify(mOffloadCtrl).dump(any()); verify(mOffloadCtrl).dump(any()); mLooper.stopAutoDispatch(); } } // TODO: Test that a request for hotspot mode doesn't interfere with an // TODO: Test that a request for hotspot mode doesn't interfere with an Loading