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

Commit 3fe660bc authored by markchien's avatar markchien
Browse files

Allow opening tethering when data saver ON

When data saver enabled, tethering would be OFF.
Currently settings would not allow user to turning tethering back.
After aosp/1181583 is merged, user can turn tethering back without
turning data saver OFF.

Bug: 145711175
Bug: 142374233
Test: atest TetheringTests
      OFF/ON tethering when data saver ON

Change-Id: I59e662ba771a563f5f1766ba29e05246b8280220
parent caa81001
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -57,9 +57,6 @@ interface INetworkPolicyManager {
    @UnsupportedAppUsage
    boolean getRestrictBackground();

    /** Callback used to change internal state on tethering */
    void onTetheringChanged(String iface, boolean tethering);

    /** Gets the restrict background status based on the caller's UID:
        1 - disabled
        2 - whitelisted
+22 −13
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
@@ -64,8 +65,8 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.ITetheringEventCallback;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -176,7 +177,6 @@ public class Tethering {
    private final Context mContext;
    private final ArrayMap<String, TetherState> mTetherStates;
    private final BroadcastReceiver mStateReceiver;
    private final INetworkPolicyManager mPolicyManager;
    private final Looper mLooper;
    private final StateMachine mTetherMasterSM;
    private final OffloadController mOffloadController;
@@ -206,12 +206,12 @@ public class Tethering {
    private boolean mWifiTetherRequested;
    private Network mTetherUpstream;
    private TetherStatesParcel mTetherStatesParcel;
    private boolean mDataSaverEnabled = false;

    public Tethering(TetheringDependencies deps) {
        mLog.mark("Tethering.constructed");
        mDeps = deps;
        mContext = mDeps.getContext();
        mPolicyManager = mDeps.getINetworkPolicyManager();
        mNetd = mDeps.getINetd(mContext);
        mLooper = mDeps.getTetheringLooper();

@@ -288,6 +288,7 @@ public class Tethering {
        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
        filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
        filter.addAction(ACTION_RESTRICT_BACKGROUND_CHANGED);
        mContext.registerReceiver(mStateReceiver, filter, null, handler);
    }

@@ -484,7 +485,7 @@ public class Tethering {
    }

    private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        final BluetoothAdapter adapter = mDeps.getBluetoothAdapter();
        if (adapter == null || !adapter.isEnabled()) {
            Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
                    + (adapter == null));
@@ -775,6 +776,9 @@ public class Tethering {
            } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) {
                mLog.log("OBSERVED user restrictions changed");
                handleUserRestrictionAction();
            } else if (action.equals(ACTION_RESTRICT_BACKGROUND_CHANGED)) {
                mLog.log("OBSERVED data saver changed");
                handleDataSaverChanged();
            }
        }

@@ -885,6 +889,20 @@ public class Tethering {
        private void handleUserRestrictionAction() {
            mTetheringRestriction.onUserRestrictionsChanged();
        }

        private void handleDataSaverChanged() {
            final ConnectivityManager connMgr = (ConnectivityManager) mContext.getSystemService(
                    Context.CONNECTIVITY_SERVICE);
            final boolean isDataSaverEnabled = connMgr.getRestrictBackgroundStatus()
                    != ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;

            if (mDataSaverEnabled == isDataSaverEnabled) return;

            mDataSaverEnabled = isDataSaverEnabled;
            if (mDataSaverEnabled) {
                untetherAll();
            }
        }
    }

    @VisibleForTesting
@@ -1982,15 +2000,6 @@ public class Tethering {

        mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));

        try {
            // Notify that we're tethering (or not) this interface.
            // This is how data saver for instance knows if the user explicitly
            // turned on tethering (thus keeping us from being in data saver mode).
            mPolicyManager.onTetheringChanged(iface, state == IpServer.STATE_TETHERED);
        } catch (RemoteException e) {
            // Not really very much we can do here.
        }

        // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
        // Thus we give a chance for TetherMasterSM to recover to InitialState
        // by sending CMD_CLEAR_ERROR
+6 −9
Original line number Diff line number Diff line
@@ -16,9 +16,9 @@

package com.android.server.connectivity.tethering;

import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.NetworkRequest;
import android.net.ip.IpServer;
import android.net.util.SharedLog;
@@ -105,14 +105,6 @@ public abstract class TetheringDependencies {
                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
    }

    /**
     * Get a reference to INetworkPolicyManager to be used by tethering.
     */
    public INetworkPolicyManager getINetworkPolicyManager() {
        return INetworkPolicyManager.Stub.asInterface(
                ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
    }

    /**
     * Get a reference to INetd to be used by tethering.
     */
@@ -130,4 +122,9 @@ public abstract class TetheringDependencies {
     *  Get Context of TetheringSerice.
     */
    public abstract Context getContext();

    /**
     * Get a reference to BluetoothAdapter to be used by tethering.
     */
    public abstract BluetoothAdapter getBluetoothAdapter();
}
+6 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED;
import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.net.IIntResultListener;
@@ -376,6 +377,11 @@ public class TetheringService extends Service {
                    }
                    return INetworkStackConnector.Stub.asInterface(connector);
                }

                @Override
                public BluetoothAdapter getBluetoothAdapter() {
                    return BluetoothAdapter.getDefaultAdapter();
                }
            };
        }
        return mDeps;
+59 −5
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@ package com.android.server.connectivity.tethering;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.RouteInfo.RTN_UNICAST;
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
@@ -53,6 +56,7 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
@@ -61,6 +65,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -69,6 +74,7 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.ITetheringEventCallback;
@@ -133,6 +139,7 @@ import java.net.Inet4Address;
import java.net.Inet6Address;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Vector;

@RunWith(AndroidJUnit4.class)
@@ -167,6 +174,7 @@ public class TetheringTest {
    @Mock private INetd mNetd;
    @Mock private UserManager mUserManager;
    @Mock private NetworkRequest mNetworkRequest;
    @Mock private ConnectivityManager mCm;

    private final MockIpServerDependencies mIpServerDependencies =
            spy(new MockIpServerDependencies());
@@ -218,6 +226,7 @@ public class TetheringTest {
            if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
            if (Context.USER_SERVICE.equals(name)) return mUserManager;
            if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
            if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
            return super.getSystemService(name);
        }

@@ -339,11 +348,6 @@ public class TetheringTest {
            return mNMService;
        }

        @Override
        public INetworkPolicyManager getINetworkPolicyManager() {
            return mPolicyManager;
        }

        @Override
        public INetd getINetd(Context context) {
            return mNetd;
@@ -358,6 +362,12 @@ public class TetheringTest {
        public Context getContext() {
            return mServiceContext;
        }

        @Override
        public BluetoothAdapter getBluetoothAdapter() {
            // TODO: add test for bluetooth tethering.
            return null;
        }
    }

    private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4,
@@ -1349,6 +1359,50 @@ public class TetheringTest {
        workingWifiP2pGroupClient(false);
    }

    private void setDataSaverEnabled(boolean enabled) {
        final Intent intent = new Intent(ACTION_RESTRICT_BACKGROUND_CHANGED);
        mServiceContext.sendBroadcastAsUser(intent, UserHandle.ALL);

        final int status = enabled ? RESTRICT_BACKGROUND_STATUS_ENABLED
                : RESTRICT_BACKGROUND_STATUS_DISABLED;
        when(mCm.getRestrictBackgroundStatus()).thenReturn(status);
        mLooper.dispatchAll();
    }

    @Test
    public void testDataSaverChanged() {
        // Start Tethering.
        final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
        runUsbTethering(upstreamState);
        assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME);
        // Data saver is ON.
        setDataSaverEnabled(true);
        // Verify that tethering should be disabled.
        verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
        mTethering.interfaceRemoved(TEST_USB_IFNAME);
        mLooper.dispatchAll();
        assertEquals(mTethering.getTetheredIfaces(), new String[0]);
        reset(mUsbManager);

        runUsbTethering(upstreamState);
        // Verify that user can start tethering again without turning OFF data saver.
        assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME);

        // If data saver is keep ON with change event, tethering should not be OFF this time.
        setDataSaverEnabled(true);
        verify(mUsbManager, times(0)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
        assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME);

        // If data saver is turned OFF, it should not change tethering.
        setDataSaverEnabled(false);
        verify(mUsbManager, times(0)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
        assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME);
    }

    private static <T> void assertContains(Collection<T> collection, T element) {
        assertTrue(element + " not found in " + collection, collection.contains(element));
    }

    // TODO: Test that a request for hotspot mode doesn't interfere with an
    // already operating tethering mode interface.
}
Loading