Merge "Allow opening tethering when data saver ON"
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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.
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user