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_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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -51,6 +54,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;
|
||||
@@ -59,6 +63,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;
|
||||
@@ -67,6 +72,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;
|
||||
@@ -132,6 +138,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)
|
||||
@@ -166,6 +173,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());
|
||||
@@ -217,6 +225,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);
|
||||
}
|
||||
|
||||
@@ -338,11 +347,6 @@ public class TetheringTest {
|
||||
return mNMService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public INetworkPolicyManager getINetworkPolicyManager() {
|
||||
return mPolicyManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public INetd getINetd(Context context) {
|
||||
return mNetd;
|
||||
@@ -357,6 +361,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,
|
||||
@@ -1348,6 +1358,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.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user