Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ee6a954 authored by markchien's avatar markchien Committed by Mark Chien
Browse files

Make members final in TetheringService

1. Move isTetheringSupport logic from TetheringService to Tethering.
2. Small readability improvement in TetheringTest. Also change
config_tether_upstream_automatic from false to true in TetheringTest.
So TetheringTests would default run automatic select upstream flow
instead of selecting by legacy perferred network type list.

Bug: 153609486
Test: atest TetheringTest
Change-Id: I5a82a6347f62d3a7031db5c56e8e0c8530dafd8f
Merged-In: I5a82a6347f62d3a7031db5c56e8e0c8530dafd8f
parent 97e6f46c
Loading
Loading
Loading
Loading
+27 −9
Original line number Original line Diff line number Diff line
@@ -109,8 +109,10 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ResultReceiver;
import android.os.ServiceSpecificException;
import android.os.ServiceSpecificException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.TextUtils;
@@ -228,6 +230,7 @@ public class Tethering {
    private final ConnectedClientsTracker mConnectedClientsTracker;
    private final ConnectedClientsTracker mConnectedClientsTracker;
    private final TetheringThreadExecutor mExecutor;
    private final TetheringThreadExecutor mExecutor;
    private final TetheringNotificationUpdater mNotificationUpdater;
    private final TetheringNotificationUpdater mNotificationUpdater;
    private final UserManager mUserManager;
    private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
    private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
    // All the usage of mTetheringEventCallback should run in the same thread.
    // All the usage of mTetheringEventCallback should run in the same thread.
    private ITetheringEventCallback mTetheringEventCallback = null;
    private ITetheringEventCallback mTetheringEventCallback = null;
@@ -305,23 +308,24 @@ public class Tethering {


        mStateReceiver = new StateReceiver();
        mStateReceiver = new StateReceiver();


        final UserManager userManager = (UserManager) mContext.getSystemService(
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
                Context.USER_SERVICE);
        mTetheringRestriction = new UserRestrictionActionListener(
        mTetheringRestriction = new UserRestrictionActionListener(
                userManager, this, mNotificationUpdater);
                mUserManager, this, mNotificationUpdater);
        mExecutor = new TetheringThreadExecutor(mHandler);
        mExecutor = new TetheringThreadExecutor(mHandler);
        mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
        mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
        mNetdCallback = new NetdCallback();
        mNetdCallback = new NetdCallback();


        // Load tethering configuration.
        // Load tethering configuration.
        updateConfiguration();
        updateConfiguration();

        startStateMachineUpdaters();
    }
    }


    /**
    /**
     * Start to register callbacks.
     * Start to register callbacks.
     * Call this function when tethering is ready to handle callback events.
     * Call this function when tethering is ready to handle callback events.
     */
     */
    public void startStateMachineUpdaters() {
    private void startStateMachineUpdaters() {
        try {
        try {
            mNetd.registerUnsolicitedEventListener(mNetdCallback);
            mNetd.registerUnsolicitedEventListener(mNetdCallback);
        } catch (RemoteException e) {
        } catch (RemoteException e) {
@@ -779,7 +783,7 @@ public class Tethering {


    // TODO: Figure out how to update for local hotspot mode interfaces.
    // TODO: Figure out how to update for local hotspot mode interfaces.
    private void sendTetherStateChangedBroadcast() {
    private void sendTetherStateChangedBroadcast() {
        if (!mDeps.isTetheringSupported()) return;
        if (!isTetheringSupported()) return;


        final ArrayList<String> availableList = new ArrayList<>();
        final ArrayList<String> availableList = new ArrayList<>();
        final ArrayList<String> tetherList = new ArrayList<>();
        final ArrayList<String> tetherList = new ArrayList<>();
@@ -1020,14 +1024,14 @@ public class Tethering {


    @VisibleForTesting
    @VisibleForTesting
    protected static class UserRestrictionActionListener {
    protected static class UserRestrictionActionListener {
        private final UserManager mUserManager;
        private final UserManager mUserMgr;
        private final Tethering mWrapper;
        private final Tethering mWrapper;
        private final TetheringNotificationUpdater mNotificationUpdater;
        private final TetheringNotificationUpdater mNotificationUpdater;
        public boolean mDisallowTethering;
        public boolean mDisallowTethering;


        public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper,
        public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper,
                @NonNull TetheringNotificationUpdater updater) {
                @NonNull TetheringNotificationUpdater updater) {
            mUserManager = um;
            mUserMgr = um;
            mWrapper = wrapper;
            mWrapper = wrapper;
            mNotificationUpdater = updater;
            mNotificationUpdater = updater;
            mDisallowTethering = false;
            mDisallowTethering = false;
@@ -1037,7 +1041,7 @@ public class Tethering {
            // getUserRestrictions gets restriction for this process' user, which is the primary
            // getUserRestrictions gets restriction for this process' user, which is the primary
            // user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary
            // user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary
            // user. See UserManager.DISALLOW_CONFIG_TETHERING.
            // user. See UserManager.DISALLOW_CONFIG_TETHERING.
            final Bundle restrictions = mUserManager.getUserRestrictions();
            final Bundle restrictions = mUserMgr.getUserRestrictions();
            final boolean newlyDisallowed =
            final boolean newlyDisallowed =
                    restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
                    restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
            final boolean prevDisallowed = mDisallowTethering;
            final boolean prevDisallowed = mDisallowTethering;
@@ -1988,7 +1992,7 @@ public class Tethering {
        mHandler.post(() -> {
        mHandler.post(() -> {
            mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission));
            mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission));
            final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
            final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
            parcel.tetheringSupported = mDeps.isTetheringSupported();
            parcel.tetheringSupported = isTetheringSupported();
            parcel.upstreamNetwork = mTetherUpstream;
            parcel.upstreamNetwork = mTetherUpstream;
            parcel.config = mConfig.toStableParcelable();
            parcel.config = mConfig.toStableParcelable();
            parcel.states =
            parcel.states =
@@ -2111,6 +2115,20 @@ public class Tethering {
        }
        }
    }
    }


    // if ro.tether.denied = true we default to no tethering
    // gservices could set the secure setting to 1 though to enable it on a build where it
    // had previously been turned off.
    boolean isTetheringSupported() {
        final int defaultVal =
                SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
        final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
        final boolean tetherEnabledInSettings = tetherSupported
                && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);

        return tetherEnabledInSettings && hasTetherableConfiguration();
    }

    void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
    void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
        // Binder.java closes the resource for us.
        // Binder.java closes the resource for us.
        @SuppressWarnings("resource")
        @SuppressWarnings("resource")
+71 −114
Original line number Original line Diff line number Diff line
@@ -40,15 +40,12 @@ import android.net.TetheringRequestParcel;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.ip.IpServer;
import android.net.ip.IpServer;
import android.net.util.SharedLog;
import android.os.Binder;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Looper;
import android.os.Looper;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ResultReceiver;
import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings;
import android.util.Log;
import android.util.Log;


@@ -68,21 +65,14 @@ import java.io.PrintWriter;
public class TetheringService extends Service {
public class TetheringService extends Service {
    private static final String TAG = TetheringService.class.getSimpleName();
    private static final String TAG = TetheringService.class.getSimpleName();


    private final SharedLog mLog = new SharedLog(TAG);
    private TetheringConnector mConnector;
    private TetheringConnector mConnector;
    private Context mContext;
    private TetheringDependencies mDeps;
    private Tethering mTethering;
    private UserManager mUserManager;


    @Override
    @Override
    public void onCreate() {
    public void onCreate() {
        mLog.mark("onCreate");
        final TetheringDependencies deps = makeTetheringDependencies();
        mDeps = getTetheringDependencies();
        // The Tethering object needs a fully functional context to start, so this can't be done
        mContext = mDeps.getContext();
        // in the constructor.
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this);
        mTethering = makeTethering(mDeps);
        mTethering.startStateMachineUpdaters();
    }
    }


    /**
    /**
@@ -94,21 +84,10 @@ public class TetheringService extends Service {
        return new Tethering(deps);
        return new Tethering(deps);
    }
    }


    /**
     * Create a binder connector for the system server to communicate with the tethering.
     */
    private synchronized IBinder makeConnector() {
        if (mConnector == null) {
            mConnector = new TetheringConnector(mTethering, TetheringService.this);
        }
        return mConnector;
    }

    @NonNull
    @NonNull
    @Override
    @Override
    public IBinder onBind(Intent intent) {
    public IBinder onBind(Intent intent) {
        mLog.mark("onBind");
        return mConnector;
        return makeConnector();
    }
    }


    private static class TetheringConnector extends ITetheringConnector.Stub {
    private static class TetheringConnector extends ITetheringConnector.Stub {
@@ -248,7 +227,7 @@ public class TetheringService extends Service {
                    listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
                    listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
                    return true;
                    return true;
                }
                }
                if (!mService.isTetheringSupported()) {
                if (!mTethering.isTetheringSupported()) {
                    listener.onResult(TETHER_ERROR_UNSUPPORTED);
                    listener.onResult(TETHER_ERROR_UNSUPPORTED);
                    return true;
                    return true;
                }
                }
@@ -266,7 +245,7 @@ public class TetheringService extends Service {
                receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
                receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
                return true;
                return true;
            }
            }
            if (!mService.isTetheringSupported()) {
            if (!mTethering.isTetheringSupported()) {
                receiver.send(TETHER_ERROR_UNSUPPORTED, null);
                receiver.send(TETHER_ERROR_UNSUPPORTED, null);
                return true;
                return true;
            }
            }
@@ -300,20 +279,6 @@ public class TetheringService extends Service {
        }
        }
    }
    }


    // if ro.tether.denied = true we default to no tethering
    // gservices could set the secure setting to 1 though to enable it on a build where it
    // had previously been turned off.
    private boolean isTetheringSupported() {
        final int defaultVal =
                SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
        final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
        final boolean tetherEnabledInSettings = tetherSupported
                && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);

        return tetherEnabledInSettings && mTethering.hasTetherableConfiguration();
    }

    /**
    /**
     * Check if the package is a allowed to write settings. This also accounts that such an access
     * Check if the package is a allowed to write settings. This also accounts that such an access
     * happened.
     * happened.
@@ -332,9 +297,8 @@ public class TetheringService extends Service {
     * An injection method for testing.
     * An injection method for testing.
     */
     */
    @VisibleForTesting
    @VisibleForTesting
    public TetheringDependencies getTetheringDependencies() {
    public TetheringDependencies makeTetheringDependencies() {
        if (mDeps == null) {
        return new TetheringDependencies() {
            mDeps = new TetheringDependencies() {
            @Override
            @Override
            public NetworkRequest getDefaultNetworkRequest() {
            public NetworkRequest getDefaultNetworkRequest() {
                // TODO: b/147280869, add a proper system API to replace this.
                // TODO: b/147280869, add a proper system API to replace this.
@@ -355,11 +319,6 @@ public class TetheringService extends Service {
                return tetherThread.getLooper();
                return tetherThread.getLooper();
            }
            }


                @Override
                public boolean isTetheringSupported() {
                    return TetheringService.this.isTetheringSupported();
                }

            @Override
            @Override
            public Context getContext() {
            public Context getContext() {
                return TetheringService.this;
                return TetheringService.this;
@@ -413,6 +372,4 @@ public class TetheringService extends Service {
            }
            }
        };
        };
    }
    }
        return mDeps;
    }
}
}
+9 −10
Original line number Original line Diff line number Diff line
@@ -83,8 +83,7 @@ public final class TetheringServiceTest {
        mTetheringConnector = mockConnector.getTetheringConnector();
        mTetheringConnector = mockConnector.getTetheringConnector();
        final MockTetheringService service = mockConnector.getService();
        final MockTetheringService service = mockConnector.getService();
        mTethering = service.getTethering();
        mTethering = service.getTethering();
        verify(mTethering).startStateMachineUpdaters();
        when(mTethering.isTetheringSupported()).thenReturn(true);
        when(mTethering.hasTetherableConfiguration()).thenReturn(true);
    }
    }


    @After
    @After
@@ -97,7 +96,7 @@ public final class TetheringServiceTest {
        when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
        when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
        final TestTetheringResult result = new TestTetheringResult();
        final TestTetheringResult result = new TestTetheringResult();
        mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
        mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
        verify(mTethering).hasTetherableConfiguration();
        verify(mTethering).isTetheringSupported();
        verify(mTethering).tether(TEST_IFACE_NAME);
        verify(mTethering).tether(TEST_IFACE_NAME);
        verifyNoMoreInteractions(mTethering);
        verifyNoMoreInteractions(mTethering);
        result.assertResult(TETHER_ERROR_NO_ERROR);
        result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -109,7 +108,7 @@ public final class TetheringServiceTest {
        final TestTetheringResult result = new TestTetheringResult();
        final TestTetheringResult result = new TestTetheringResult();
        mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
        mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
                result);
                result);
        verify(mTethering).hasTetherableConfiguration();
        verify(mTethering).isTetheringSupported();
        verify(mTethering).untether(TEST_IFACE_NAME);
        verify(mTethering).untether(TEST_IFACE_NAME);
        verifyNoMoreInteractions(mTethering);
        verifyNoMoreInteractions(mTethering);
        result.assertResult(TETHER_ERROR_NO_ERROR);
        result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -121,7 +120,7 @@ public final class TetheringServiceTest {
        final TestTetheringResult result = new TestTetheringResult();
        final TestTetheringResult result = new TestTetheringResult();
        mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG,
        mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG,
                TEST_ATTRIBUTION_TAG, result);
                TEST_ATTRIBUTION_TAG, result);
        verify(mTethering).hasTetherableConfiguration();
        verify(mTethering).isTetheringSupported();
        verify(mTethering).setUsbTethering(true /* enable */);
        verify(mTethering).setUsbTethering(true /* enable */);
        verifyNoMoreInteractions(mTethering);
        verifyNoMoreInteractions(mTethering);
        result.assertResult(TETHER_ERROR_NO_ERROR);
        result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -133,7 +132,7 @@ public final class TetheringServiceTest {
        final TetheringRequestParcel request = new TetheringRequestParcel();
        final TetheringRequestParcel request = new TetheringRequestParcel();
        request.tetheringType = TETHERING_WIFI;
        request.tetheringType = TETHERING_WIFI;
        mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
        mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
        verify(mTethering).hasTetherableConfiguration();
        verify(mTethering).isTetheringSupported();
        verify(mTethering).startTethering(eq(request), eq(result));
        verify(mTethering).startTethering(eq(request), eq(result));
        verifyNoMoreInteractions(mTethering);
        verifyNoMoreInteractions(mTethering);
    }
    }
@@ -143,7 +142,7 @@ public final class TetheringServiceTest {
        final TestTetheringResult result = new TestTetheringResult();
        final TestTetheringResult result = new TestTetheringResult();
        mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
        mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
                result);
                result);
        verify(mTethering).hasTetherableConfiguration();
        verify(mTethering).isTetheringSupported();
        verify(mTethering).stopTethering(TETHERING_WIFI);
        verify(mTethering).stopTethering(TETHERING_WIFI);
        verifyNoMoreInteractions(mTethering);
        verifyNoMoreInteractions(mTethering);
        result.assertResult(TETHER_ERROR_NO_ERROR);
        result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -154,7 +153,7 @@ public final class TetheringServiceTest {
        final ResultReceiver result = new ResultReceiver(null);
        final ResultReceiver result = new ResultReceiver(null);
        mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result,
        mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result,
                true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG);
                true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG);
        verify(mTethering).hasTetherableConfiguration();
        verify(mTethering).isTetheringSupported();
        verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI),
        verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI),
                eq(result), eq(true) /* showEntitlementUi */);
                eq(result), eq(true) /* showEntitlementUi */);
        verifyNoMoreInteractions(mTethering);
        verifyNoMoreInteractions(mTethering);
@@ -181,7 +180,7 @@ public final class TetheringServiceTest {
    public void testStopAllTethering() throws Exception {
    public void testStopAllTethering() throws Exception {
        final TestTetheringResult result = new TestTetheringResult();
        final TestTetheringResult result = new TestTetheringResult();
        mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
        mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
        verify(mTethering).hasTetherableConfiguration();
        verify(mTethering).isTetheringSupported();
        verify(mTethering).untetherAll();
        verify(mTethering).untetherAll();
        verifyNoMoreInteractions(mTethering);
        verifyNoMoreInteractions(mTethering);
        result.assertResult(TETHER_ERROR_NO_ERROR);
        result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -191,7 +190,7 @@ public final class TetheringServiceTest {
    public void testIsTetheringSupported() throws Exception {
    public void testIsTetheringSupported() throws Exception {
        final TestTetheringResult result = new TestTetheringResult();
        final TestTetheringResult result = new TestTetheringResult();
        mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
        mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
        verify(mTethering).hasTetherableConfiguration();
        verify(mTethering).isTetheringSupported();
        verifyNoMoreInteractions(mTethering);
        verifyNoMoreInteractions(mTethering);
        result.assertResult(TETHER_ERROR_NO_ERROR);
        result.assertResult(TETHER_ERROR_NO_ERROR);
    }
    }
+32 −24
Original line number Original line Diff line number Diff line
@@ -485,18 +485,6 @@ public class TetheringTest {
        MockitoAnnotations.initMocks(this);
        MockitoAnnotations.initMocks(this);
        when(mResources.getStringArray(R.array.config_tether_dhcp_range))
        when(mResources.getStringArray(R.array.config_tether_dhcp_range))
                .thenReturn(new String[0]);
                .thenReturn(new String[0]);
        when(mResources.getStringArray(R.array.config_tether_usb_regexs))
                .thenReturn(new String[] { "test_rndis\\d" });
        when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
                .thenReturn(new String[]{ "test_wlan\\d" });
        when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
                .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
        when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
                .thenReturn(new String[0]);
        when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
                .thenReturn(new String[] { "test_ncm\\d" });
        when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
        when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false);
        when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
        when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
                false);
                false);
        when(mNetd.interfaceGetList())
        when(mNetd.interfaceGetList())
@@ -515,6 +503,7 @@ public class TetheringTest {
        mServiceContext = new TestContext(mContext);
        mServiceContext = new TestContext(mContext);
        mContentResolver = new MockContentResolver(mServiceContext);
        mContentResolver = new MockContentResolver(mServiceContext);
        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        setTetheringSupported(true /* supported */);
        mIntents = new Vector<>();
        mIntents = new Vector<>();
        mBroadcastReceiver = new BroadcastReceiver() {
        mBroadcastReceiver = new BroadcastReceiver() {
            @Override
            @Override
@@ -525,7 +514,6 @@ public class TetheringTest {
        mServiceContext.registerReceiver(mBroadcastReceiver,
        mServiceContext.registerReceiver(mBroadcastReceiver,
                new IntentFilter(ACTION_TETHER_STATE_CHANGED));
                new IntentFilter(ACTION_TETHER_STATE_CHANGED));
        mTethering = makeTethering();
        mTethering = makeTethering();
        mTethering.startStateMachineUpdaters();
        verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any());
        verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any());
        verify(mNetd).registerUnsolicitedEventListener(any());
        verify(mNetd).registerUnsolicitedEventListener(any());
        final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
        final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
@@ -536,6 +524,31 @@ public class TetheringTest {
        mPhoneStateListener = phoneListenerCaptor.getValue();
        mPhoneStateListener = phoneListenerCaptor.getValue();
    }
    }


    private void setTetheringSupported(final boolean supported) {
        Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED,
                supported ? 1 : 0);
        when(mUserManager.hasUserRestriction(
                UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(!supported);
        // Setup tetherable configuration.
        when(mResources.getStringArray(R.array.config_tether_usb_regexs))
                .thenReturn(new String[] { "test_rndis\\d" });
        when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
                .thenReturn(new String[]{ "test_wlan\\d" });
        when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
                .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
        when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
                .thenReturn(new String[0]);
        when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
                .thenReturn(new String[] { "test_ncm\\d" });
        when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
        when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(true);
    }

    private void initTetheringUpstream(UpstreamNetworkState upstreamState) {
        when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
    }

    private Tethering makeTethering() {
    private Tethering makeTethering() {
        mTetheringDependencies.reset();
        mTetheringDependencies.reset();
        return new Tethering(mTetheringDependencies);
        return new Tethering(mTetheringDependencies);
@@ -672,9 +685,7 @@ public class TetheringTest {
    }
    }


    private void prepareUsbTethering(UpstreamNetworkState upstreamState) {
    private void prepareUsbTethering(UpstreamNetworkState upstreamState) {
        when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
        initTetheringUpstream(upstreamState);
        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
                .thenReturn(upstreamState);


        // Emulate pressing the USB tethering button in Settings UI.
        // Emulate pressing the USB tethering button in Settings UI.
        mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null);
        mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null);
@@ -700,7 +711,7 @@ public class TetheringTest {
        verify(mNetd, times(1)).interfaceGetList();
        verify(mNetd, times(1)).interfaceGetList();


        // UpstreamNetworkMonitor should receive selected upstream
        // UpstreamNetworkMonitor should receive selected upstream
        verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
        verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream();
        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
    }
    }


@@ -872,8 +883,7 @@ public class TetheringTest {


        // Then 464xlat comes up
        // Then 464xlat comes up
        upstreamState = buildMobile464xlatUpstreamState();
        upstreamState = buildMobile464xlatUpstreamState();
        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
        initTetheringUpstream(upstreamState);
                .thenReturn(upstreamState);


        // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
        // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
        mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
        mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
@@ -1344,9 +1354,7 @@ public class TetheringTest {
        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
        // 2. Enable wifi tethering.
        // 2. Enable wifi tethering.
        UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
        UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
        when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
        initTetheringUpstream(upstreamState);
        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
                .thenReturn(upstreamState);
        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
        when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
        mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
        mLooper.dispatchAll();
        mLooper.dispatchAll();
@@ -1723,7 +1731,7 @@ public class TetheringTest {
        final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
        final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
                mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
                mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
        final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
        final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
        initTetheringUpstream(upstreamState);
        stateMachine.chooseUpstreamType(true);
        stateMachine.chooseUpstreamType(true);


        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(eq(upstreamState.network));
        verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(eq(upstreamState.network));
@@ -1735,7 +1743,7 @@ public class TetheringTest {
        final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
        final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
                mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
                mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
        final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
        final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
        when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
        initTetheringUpstream(upstreamState);
        stateMachine.chooseUpstreamType(true);
        stateMachine.chooseUpstreamType(true);


        stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState);
        stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState);