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

Commit bd7fa995 authored by Mark Chien's avatar Mark Chien Committed by Gerrit Code Review
Browse files

Merge "Allow opening tethering when data saver ON"

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


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


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


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


    private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
    private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
        final BluetoothAdapter adapter = mDeps.getBluetoothAdapter();
        if (adapter == null || !adapter.isEnabled()) {
        if (adapter == null || !adapter.isEnabled()) {
            Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
            Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
                    + (adapter == null));
                    + (adapter == null));
@@ -775,6 +776,9 @@ public class Tethering {
            } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) {
            } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) {
                mLog.log("OBSERVED user restrictions changed");
                mLog.log("OBSERVED user restrictions changed");
                handleUserRestrictionAction();
                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() {
        private void handleUserRestrictionAction() {
            mTetheringRestriction.onUserRestrictionsChanged();
            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
    @VisibleForTesting
@@ -1982,15 +2000,6 @@ public class Tethering {


        mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
        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.
        // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
        // Thus we give a chance for TetherMasterSM to recover to InitialState
        // Thus we give a chance for TetherMasterSM to recover to InitialState
        // by sending CMD_CLEAR_ERROR
        // by sending CMD_CLEAR_ERROR
+6 −9
Original line number Original line Diff line number Diff line
@@ -16,9 +16,9 @@


package com.android.server.connectivity.tethering;
package com.android.server.connectivity.tethering;


import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Context;
import android.net.INetd;
import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.NetworkRequest;
import android.net.NetworkRequest;
import android.net.ip.IpServer;
import android.net.ip.IpServer;
import android.net.util.SharedLog;
import android.net.util.SharedLog;
@@ -105,14 +105,6 @@ public abstract class TetheringDependencies {
                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
                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.
     * Get a reference to INetd to be used by tethering.
     */
     */
@@ -130,4 +122,9 @@ public abstract class TetheringDependencies {
     *  Get Context of TetheringSerice.
     *  Get Context of TetheringSerice.
     */
     */
    public abstract Context getContext();
    public abstract Context getContext();

    /**
     * Get a reference to BluetoothAdapter to be used by tethering.
     */
    public abstract BluetoothAdapter getBluetoothAdapter();
}
}
+6 −0
Original line number Original line 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 static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR;


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

                @Override
                public BluetoothAdapter getBluetoothAdapter() {
                    return BluetoothAdapter.getDefaultAdapter();
                }
            };
            };
        }
        }
        return mDeps;
        return mDeps;
+59 −5
Original line number Original line 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_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
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.RouteInfo.RTN_UNICAST;
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
@@ -51,6 +54,7 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.times;
@@ -59,6 +63,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;


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


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


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


@@ -338,11 +347,6 @@ public class TetheringTest {
            return mNMService;
            return mNMService;
        }
        }


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

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

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


    private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4,
    private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4,
@@ -1348,6 +1358,50 @@ public class TetheringTest {
        workingWifiP2pGroupClient(false);
        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
    // TODO: Test that a request for hotspot mode doesn't interfere with an
    // already operating tethering mode interface.
    // already operating tethering mode interface.
}
}
Loading