Merge "Allow opening tethering when data saver ON"

This commit is contained in:
Mark Chien
2020-01-15 06:58:29 +00:00
committed by Gerrit Code Review
4 changed files with 93 additions and 27 deletions

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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.
}