Merge "Add Entitlement Manger to encapsulate provisioning mechanics"
am: 1c66fd2d67
Change-Id: I5793f0b7d0c082a05e7d374d8b3a6d77cab6094d
This commit is contained in:
@@ -23,24 +23,18 @@ import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
|
|||||||
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
||||||
import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
|
import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
|
||||||
import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
|
import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
|
||||||
import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
|
|
||||||
import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
|
import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
|
||||||
import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER;
|
import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER;
|
||||||
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
|
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
|
||||||
import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
|
|
||||||
import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
|
|
||||||
import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
|
|
||||||
import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
|
|
||||||
import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
|
|
||||||
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
|
|
||||||
import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
|
|
||||||
import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
|
|
||||||
import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
|
|
||||||
import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
|
import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
|
||||||
import static android.net.ConnectivityManager.TETHERING_INVALID;
|
import static android.net.ConnectivityManager.TETHERING_INVALID;
|
||||||
import static android.net.ConnectivityManager.TETHERING_USB;
|
import static android.net.ConnectivityManager.TETHERING_USB;
|
||||||
import static android.net.ConnectivityManager.TETHERING_WIFI;
|
import static android.net.ConnectivityManager.TETHERING_WIFI;
|
||||||
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
|
||||||
|
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
|
||||||
|
import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
|
||||||
|
import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
|
||||||
|
import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
|
||||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
|
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
|
||||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
|
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
|
||||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
|
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
|
||||||
@@ -50,6 +44,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
|
|||||||
import static android.net.wifi.WifiManager.IFACE_IP_MODE_UNSPECIFIED;
|
import static android.net.wifi.WifiManager.IFACE_IP_MODE_UNSPECIFIED;
|
||||||
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
|
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
|
||||||
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
|
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
|
||||||
|
|
||||||
import static com.android.server.ConnectivityService.SHORT_ARG;
|
import static com.android.server.ConnectivityService.SHORT_ARG;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
@@ -60,7 +55,6 @@ import android.bluetooth.BluetoothPan;
|
|||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.bluetooth.BluetoothProfile.ServiceListener;
|
import android.bluetooth.BluetoothProfile.ServiceListener;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
@@ -68,7 +62,6 @@ import android.content.res.Resources;
|
|||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbManager;
|
||||||
import android.net.INetworkPolicyManager;
|
import android.net.INetworkPolicyManager;
|
||||||
import android.net.INetworkStatsService;
|
import android.net.INetworkStatsService;
|
||||||
import android.net.ip.IpServer;
|
|
||||||
import android.net.IpPrefix;
|
import android.net.IpPrefix;
|
||||||
import android.net.LinkAddress;
|
import android.net.LinkAddress;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
@@ -76,7 +69,7 @@ import android.net.Network;
|
|||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.net.NetworkState;
|
import android.net.NetworkState;
|
||||||
import android.net.NetworkUtils;
|
import android.net.NetworkUtils;
|
||||||
import android.net.RouteInfo;
|
import android.net.ip.IpServer;
|
||||||
import android.net.util.InterfaceSet;
|
import android.net.util.InterfaceSet;
|
||||||
import android.net.util.PrefixUtils;
|
import android.net.util.PrefixUtils;
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
@@ -89,15 +82,12 @@ import android.os.INetworkManagementService;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.PersistableBundle;
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ResultReceiver;
|
import android.os.ResultReceiver;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.os.UserManagerInternal;
|
import android.os.UserManagerInternal;
|
||||||
import android.os.UserManagerInternal.UserRestrictionsListener;
|
import android.os.UserManagerInternal.UserRestrictionsListener;
|
||||||
import android.provider.Settings;
|
|
||||||
import android.telephony.CarrierConfigManager;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -113,6 +103,7 @@ import com.android.internal.util.Protocol;
|
|||||||
import com.android.internal.util.State;
|
import com.android.internal.util.State;
|
||||||
import com.android.internal.util.StateMachine;
|
import com.android.internal.util.StateMachine;
|
||||||
import com.android.server.LocalServices;
|
import com.android.server.LocalServices;
|
||||||
|
import com.android.server.connectivity.tethering.EntitlementManager;
|
||||||
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
|
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
|
||||||
import com.android.server.connectivity.tethering.OffloadController;
|
import com.android.server.connectivity.tethering.OffloadController;
|
||||||
import com.android.server.connectivity.tethering.TetheringConfiguration;
|
import com.android.server.connectivity.tethering.TetheringConfiguration;
|
||||||
@@ -123,8 +114,6 @@ import com.android.server.net.BaseNetworkObserver;
|
|||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.Inet4Address;
|
|
||||||
import java.net.Inet6Address;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -145,18 +134,12 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
private final static boolean DBG = false;
|
private final static boolean DBG = false;
|
||||||
private final static boolean VDBG = false;
|
private final static boolean VDBG = false;
|
||||||
|
|
||||||
protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
|
|
||||||
|
|
||||||
private static final Class[] messageClasses = {
|
private static final Class[] messageClasses = {
|
||||||
Tethering.class, TetherMasterSM.class, IpServer.class
|
Tethering.class, TetherMasterSM.class, IpServer.class
|
||||||
};
|
};
|
||||||
private static final SparseArray<String> sMagicDecoderRing =
|
private static final SparseArray<String> sMagicDecoderRing =
|
||||||
MessageUtils.findMessageNames(messageClasses);
|
MessageUtils.findMessageNames(messageClasses);
|
||||||
|
|
||||||
// {@link ComponentName} of the Service used to run tether provisioning.
|
|
||||||
private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources
|
|
||||||
.getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
|
|
||||||
|
|
||||||
private static class TetherState {
|
private static class TetherState {
|
||||||
public final IpServer ipServer;
|
public final IpServer ipServer;
|
||||||
public int lastState;
|
public int lastState;
|
||||||
@@ -191,7 +174,6 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
private final INetworkStatsService mStatsService;
|
private final INetworkStatsService mStatsService;
|
||||||
private final INetworkPolicyManager mPolicyManager;
|
private final INetworkPolicyManager mPolicyManager;
|
||||||
private final Looper mLooper;
|
private final Looper mLooper;
|
||||||
private final MockableSystemProperties mSystemProperties;
|
|
||||||
private final StateMachine mTetherMasterSM;
|
private final StateMachine mTetherMasterSM;
|
||||||
private final OffloadController mOffloadController;
|
private final OffloadController mOffloadController;
|
||||||
private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
|
private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
|
||||||
@@ -200,6 +182,7 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
private final HashSet<IpServer> mForwardedDownstreams;
|
private final HashSet<IpServer> mForwardedDownstreams;
|
||||||
private final VersionedBroadcastListener mCarrierConfigChange;
|
private final VersionedBroadcastListener mCarrierConfigChange;
|
||||||
private final TetheringDependencies mDeps;
|
private final TetheringDependencies mDeps;
|
||||||
|
private final EntitlementManager mEntitlementMgr;
|
||||||
|
|
||||||
private volatile TetheringConfiguration mConfig;
|
private volatile TetheringConfiguration mConfig;
|
||||||
private InterfaceSet mCurrentUpstreamIfaceSet;
|
private InterfaceSet mCurrentUpstreamIfaceSet;
|
||||||
@@ -220,7 +203,6 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
mStatsService = statsService;
|
mStatsService = statsService;
|
||||||
mPolicyManager = policyManager;
|
mPolicyManager = policyManager;
|
||||||
mLooper = looper;
|
mLooper = looper;
|
||||||
mSystemProperties = systemProperties;
|
|
||||||
mDeps = deps;
|
mDeps = deps;
|
||||||
|
|
||||||
mPublicSync = new Object();
|
mPublicSync = new Object();
|
||||||
@@ -241,12 +223,13 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
|
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
|
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
|
||||||
|
mEntitlementMgr = mDeps.getEntitlementManager(mContext, mLog, systemProperties);
|
||||||
mCarrierConfigChange = new VersionedBroadcastListener(
|
mCarrierConfigChange = new VersionedBroadcastListener(
|
||||||
"CarrierConfigChangeListener", mContext, smHandler, filter,
|
"CarrierConfigChangeListener", mContext, smHandler, filter,
|
||||||
(Intent ignored) -> {
|
(Intent ignored) -> {
|
||||||
mLog.log("OBSERVED carrier config change");
|
mLog.log("OBSERVED carrier config change");
|
||||||
updateConfiguration();
|
updateConfiguration();
|
||||||
reevaluateSimCardProvisioning();
|
mEntitlementMgr.reevaluateSimCardProvisioning();
|
||||||
});
|
});
|
||||||
|
|
||||||
mStateReceiver = new StateReceiver();
|
mStateReceiver = new StateReceiver();
|
||||||
@@ -289,6 +272,7 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
private void updateConfiguration() {
|
private void updateConfiguration() {
|
||||||
mConfig = new TetheringConfiguration(mContext, mLog);
|
mConfig = new TetheringConfiguration(mContext, mLog);
|
||||||
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
|
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
|
||||||
|
mEntitlementMgr.updateConfiguration(mConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeUpdateConfiguration() {
|
private void maybeUpdateConfiguration() {
|
||||||
@@ -354,83 +338,54 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
|
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
|
||||||
if (!isTetherProvisioningRequired()) {
|
mEntitlementMgr.startTethering(type);
|
||||||
|
if (!mEntitlementMgr.isTetherProvisioningRequired()) {
|
||||||
enableTetheringInternal(type, true, receiver);
|
enableTetheringInternal(type, true, receiver);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
|
||||||
if (showProvisioningUi) {
|
if (showProvisioningUi) {
|
||||||
runUiTetherProvisioningAndEnable(type, receiver);
|
mEntitlementMgr.runUiTetherProvisioningAndEnable(type, proxyReceiver);
|
||||||
} else {
|
} else {
|
||||||
runSilentTetherProvisioningAndEnable(type, receiver);
|
mEntitlementMgr.runSilentTetherProvisioningAndEnable(type, proxyReceiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopTethering(int type) {
|
public void stopTethering(int type) {
|
||||||
enableTetheringInternal(type, false, null);
|
enableTetheringInternal(type, false, null);
|
||||||
if (isTetherProvisioningRequired()) {
|
mEntitlementMgr.stopTethering(type);
|
||||||
cancelTetherProvisioningRechecks(type);
|
if (mEntitlementMgr.isTetherProvisioningRequired()) {
|
||||||
|
// There are lurking bugs where the notion of "provisioning required" or
|
||||||
|
// "tethering supported" may change without notifying tethering properly, then
|
||||||
|
// tethering can't shutdown correctly.
|
||||||
|
// TODO: cancel re-check all the time
|
||||||
|
if (mDeps.isTetheringSupported()) {
|
||||||
|
mEntitlementMgr.cancelTetherProvisioningRechecks(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the device requires a provisioning check in order to enable tethering.
|
|
||||||
*
|
|
||||||
* @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
protected boolean isTetherProvisioningRequired() {
|
|
||||||
final TetheringConfiguration cfg = mConfig;
|
|
||||||
if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
|
|
||||||
|| cfg.provisioningApp.length == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (carrierConfigAffirmsEntitlementCheckNotRequired()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (cfg.provisioningApp.length == 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The logic here is aimed solely at confirming that a CarrierConfig exists
|
|
||||||
// and affirms that entitlement checks are not required.
|
|
||||||
//
|
|
||||||
// TODO: find a better way to express this, or alter the checking process
|
|
||||||
// entirely so that this is more intuitive.
|
|
||||||
private boolean carrierConfigAffirmsEntitlementCheckNotRequired() {
|
|
||||||
// Check carrier config for entitlement checks
|
|
||||||
final CarrierConfigManager configManager = (CarrierConfigManager) mContext
|
|
||||||
.getSystemService(Context.CARRIER_CONFIG_SERVICE);
|
|
||||||
if (configManager == null) return false;
|
|
||||||
|
|
||||||
final PersistableBundle carrierConfig = configManager.getConfig();
|
|
||||||
if (carrierConfig == null) return false;
|
|
||||||
|
|
||||||
// A CarrierConfigManager was found and it has a config.
|
|
||||||
final boolean isEntitlementCheckRequired = carrierConfig.getBoolean(
|
|
||||||
CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
|
|
||||||
return !isEntitlementCheckRequired;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables or disables tethering for the given type. This should only be called once
|
* Enables or disables tethering for the given type. This should only be called once
|
||||||
* provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
|
* provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
|
||||||
* for the specified interface.
|
* for the specified interface.
|
||||||
*/
|
*/
|
||||||
private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
|
private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
|
||||||
boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
|
boolean isProvisioningRequired = enable && mEntitlementMgr.isTetherProvisioningRequired();
|
||||||
int result;
|
int result;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TETHERING_WIFI:
|
case TETHERING_WIFI:
|
||||||
result = setWifiTethering(enable);
|
result = setWifiTethering(enable);
|
||||||
if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
|
if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
|
||||||
scheduleProvisioningRechecks(type);
|
mEntitlementMgr.scheduleProvisioningRechecks(type);
|
||||||
}
|
}
|
||||||
sendTetherResult(receiver, result);
|
sendTetherResult(receiver, result);
|
||||||
break;
|
break;
|
||||||
case TETHERING_USB:
|
case TETHERING_USB:
|
||||||
result = setUsbTethering(enable);
|
result = setUsbTethering(enable);
|
||||||
if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
|
if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
|
||||||
scheduleProvisioningRechecks(type);
|
mEntitlementMgr.scheduleProvisioningRechecks(type);
|
||||||
}
|
}
|
||||||
sendTetherResult(receiver, result);
|
sendTetherResult(receiver, result);
|
||||||
break;
|
break;
|
||||||
@@ -489,32 +444,14 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
? TETHER_ERROR_NO_ERROR
|
? TETHER_ERROR_NO_ERROR
|
||||||
: TETHER_ERROR_MASTER_ERROR;
|
: TETHER_ERROR_MASTER_ERROR;
|
||||||
sendTetherResult(receiver, result);
|
sendTetherResult(receiver, result);
|
||||||
if (enable && isTetherProvisioningRequired()) {
|
if (enable && mEntitlementMgr.isTetherProvisioningRequired()) {
|
||||||
scheduleProvisioningRechecks(TETHERING_BLUETOOTH);
|
mEntitlementMgr.scheduleProvisioningRechecks(TETHERING_BLUETOOTH);
|
||||||
}
|
}
|
||||||
adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
|
adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
|
||||||
}
|
}
|
||||||
}, BluetoothProfile.PAN);
|
}, BluetoothProfile.PAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runUiTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
|
|
||||||
ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
|
|
||||||
sendUiTetherProvisionIntent(type, proxyReceiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendUiTetherProvisionIntent(int type, ResultReceiver receiver) {
|
|
||||||
Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
|
|
||||||
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
|
|
||||||
intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
final long ident = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(ident);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a proxy {@link ResultReceiver} which enables tethering if the provisioning result
|
* Creates a proxy {@link ResultReceiver} which enables tethering if the provisioning result
|
||||||
* is successful before firing back up to the wrapped receiver.
|
* is successful before firing back up to the wrapped receiver.
|
||||||
@@ -546,62 +483,6 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
return receiverForSending;
|
return receiverForSending;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleProvisioningRechecks(int type) {
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
|
|
||||||
intent.putExtra(EXTRA_SET_ALARM, true);
|
|
||||||
intent.setComponent(TETHER_SERVICE);
|
|
||||||
final long ident = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
mContext.startServiceAsUser(intent, UserHandle.CURRENT);
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(ident);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runSilentTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
|
|
||||||
ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
|
|
||||||
sendSilentTetherProvisionIntent(type, proxyReceiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendSilentTetherProvisionIntent(int type, ResultReceiver receiver) {
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
|
|
||||||
intent.putExtra(EXTRA_RUN_PROVISION, true);
|
|
||||||
intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
|
|
||||||
intent.setComponent(TETHER_SERVICE);
|
|
||||||
final long ident = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
mContext.startServiceAsUser(intent, UserHandle.CURRENT);
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(ident);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cancelTetherProvisioningRechecks(int type) {
|
|
||||||
if (mDeps.isTetheringSupported()) {
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.putExtra(EXTRA_REM_TETHER_TYPE, type);
|
|
||||||
intent.setComponent(TETHER_SERVICE);
|
|
||||||
final long ident = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
mContext.startServiceAsUser(intent, UserHandle.CURRENT);
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(ident);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by the SIM card change observation code.
|
|
||||||
// TODO: De-duplicate with above code, where possible.
|
|
||||||
private void startProvisionIntent(int tetherType) {
|
|
||||||
final Intent startProvIntent = new Intent();
|
|
||||||
startProvIntent.putExtra(EXTRA_ADD_TETHER_TYPE, tetherType);
|
|
||||||
startProvIntent.putExtra(EXTRA_RUN_PROVISION, true);
|
|
||||||
startProvIntent.setComponent(TETHER_SERVICE);
|
|
||||||
mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int tether(String iface) {
|
public int tether(String iface) {
|
||||||
return tether(iface, IpServer.STATE_TETHERED);
|
return tether(iface, IpServer.STATE_TETHERED);
|
||||||
}
|
}
|
||||||
@@ -1166,30 +1047,6 @@ public class Tethering extends BaseNetworkObserver {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reevaluateSimCardProvisioning() {
|
|
||||||
if (!mConfig.hasMobileHotspotProvisionApp()) return;
|
|
||||||
if (carrierConfigAffirmsEntitlementCheckNotRequired()) return;
|
|
||||||
|
|
||||||
ArrayList<Integer> tethered = new ArrayList<>();
|
|
||||||
synchronized (mPublicSync) {
|
|
||||||
for (int i = 0; i < mTetherStates.size(); i++) {
|
|
||||||
TetherState tetherState = mTetherStates.valueAt(i);
|
|
||||||
if (tetherState.lastState != IpServer.STATE_TETHERED) {
|
|
||||||
continue; // Skip interfaces that aren't tethered.
|
|
||||||
}
|
|
||||||
String iface = mTetherStates.keyAt(i);
|
|
||||||
int interfaceType = ifaceNameToType(iface);
|
|
||||||
if (interfaceType != TETHERING_INVALID) {
|
|
||||||
tethered.add(interfaceType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int tetherType : tethered) {
|
|
||||||
startProvisionIntent(tetherType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TetherMasterSM extends StateMachine {
|
class TetherMasterSM extends StateMachine {
|
||||||
private static final int BASE_MASTER = Protocol.BASE_TETHERING;
|
private static final int BASE_MASTER = Protocol.BASE_TETHERING;
|
||||||
// an interface SM has requested Tethering/Local Hotspot
|
// an interface SM has requested Tethering/Local Hotspot
|
||||||
|
|||||||
@@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.connectivity.tethering;
|
||||||
|
|
||||||
|
import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
|
||||||
|
import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
|
||||||
|
import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
|
||||||
|
import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
|
||||||
|
import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
|
||||||
|
|
||||||
|
import static com.android.internal.R.string.config_wifi_tether_enable;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.net.util.SharedLog;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.PersistableBundle;
|
||||||
|
import android.os.ResultReceiver;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.telephony.CarrierConfigManager;
|
||||||
|
import android.util.ArraySet;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.server.connectivity.MockableSystemProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class encapsulates entitlement/provisioning mechanics
|
||||||
|
* provisioning check only applies to the use of the mobile network as an upstream
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class EntitlementManager {
|
||||||
|
private static final String TAG = EntitlementManager.class.getSimpleName();
|
||||||
|
|
||||||
|
// {@link ComponentName} of the Service used to run tether provisioning.
|
||||||
|
private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(
|
||||||
|
Resources.getSystem().getString(config_wifi_tether_enable));
|
||||||
|
protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
|
||||||
|
|
||||||
|
// The ArraySet contains enabled downstream types, ex:
|
||||||
|
// {@link ConnectivityManager.TETHERING_WIFI}
|
||||||
|
// {@link ConnectivityManager.TETHERING_USB}
|
||||||
|
// {@link ConnectivityManager.TETHERING_BLUETOOTH}
|
||||||
|
@GuardedBy("mCurrentTethers")
|
||||||
|
private final ArraySet<Integer> mCurrentTethers;
|
||||||
|
private final Context mContext;
|
||||||
|
private final MockableSystemProperties mSystemProperties;
|
||||||
|
private final SharedLog mLog;
|
||||||
|
@Nullable
|
||||||
|
private TetheringConfiguration mConfig;
|
||||||
|
|
||||||
|
public EntitlementManager(Context ctx, SharedLog log,
|
||||||
|
MockableSystemProperties systemProperties) {
|
||||||
|
mContext = ctx;
|
||||||
|
mLog = log;
|
||||||
|
mCurrentTethers = new ArraySet<Integer>();
|
||||||
|
mSystemProperties = systemProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass a new TetheringConfiguration instance each time when
|
||||||
|
* Tethering#updateConfiguration() is called.
|
||||||
|
*/
|
||||||
|
public void updateConfiguration(TetheringConfiguration conf) {
|
||||||
|
mConfig = conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell EntitlementManager that a given type of tethering has been enabled
|
||||||
|
*
|
||||||
|
* @param type Tethering type
|
||||||
|
*/
|
||||||
|
public void startTethering(int type) {
|
||||||
|
synchronized (mCurrentTethers) {
|
||||||
|
mCurrentTethers.add(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell EntitlementManager that a given type of tethering has been disabled
|
||||||
|
*
|
||||||
|
* @param type Tethering type
|
||||||
|
*/
|
||||||
|
public void stopTethering(int type) {
|
||||||
|
synchronized (mCurrentTethers) {
|
||||||
|
mCurrentTethers.remove(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the device requires a provisioning check in order to enable tethering.
|
||||||
|
*
|
||||||
|
* @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public boolean isTetherProvisioningRequired() {
|
||||||
|
if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
|
||||||
|
|| mConfig.provisioningApp.length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (carrierConfigAffirmsEntitlementCheckNotRequired()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (mConfig.provisioningApp.length == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-check tethering provisioning for enabled downstream tether types.
|
||||||
|
* Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
|
||||||
|
*/
|
||||||
|
public void reevaluateSimCardProvisioning() {
|
||||||
|
if (!mConfig.hasMobileHotspotProvisionApp()) return;
|
||||||
|
if (carrierConfigAffirmsEntitlementCheckNotRequired()) return;
|
||||||
|
|
||||||
|
final ArraySet<Integer> reevaluateType;
|
||||||
|
synchronized (mCurrentTethers) {
|
||||||
|
reevaluateType = new ArraySet<Integer>(mCurrentTethers);
|
||||||
|
}
|
||||||
|
for (Integer type : reevaluateType) {
|
||||||
|
startProvisionIntent(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The logic here is aimed solely at confirming that a CarrierConfig exists
|
||||||
|
// and affirms that entitlement checks are not required.
|
||||||
|
//
|
||||||
|
// TODO: find a better way to express this, or alter the checking process
|
||||||
|
// entirely so that this is more intuitive.
|
||||||
|
private boolean carrierConfigAffirmsEntitlementCheckNotRequired() {
|
||||||
|
// Check carrier config for entitlement checks
|
||||||
|
final CarrierConfigManager configManager = (CarrierConfigManager) mContext
|
||||||
|
.getSystemService(Context.CARRIER_CONFIG_SERVICE);
|
||||||
|
if (configManager == null) return false;
|
||||||
|
|
||||||
|
final PersistableBundle carrierConfig = configManager.getConfig();
|
||||||
|
if (carrierConfig == null) return false;
|
||||||
|
|
||||||
|
// A CarrierConfigManager was found and it has a config.
|
||||||
|
final boolean isEntitlementCheckRequired = carrierConfig.getBoolean(
|
||||||
|
CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
|
||||||
|
return !isEntitlementCheckRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runSilentTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
|
||||||
|
intent.putExtra(EXTRA_RUN_PROVISION, true);
|
||||||
|
intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
|
||||||
|
intent.setComponent(TETHER_SERVICE);
|
||||||
|
final long ident = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
mContext.startServiceAsUser(intent, UserHandle.CURRENT);
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(ident);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runUiTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
|
||||||
|
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
|
||||||
|
intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
final long ident = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(ident);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the SIM card change observation code.
|
||||||
|
// TODO: De-duplicate with above code, where possible.
|
||||||
|
private void startProvisionIntent(int tetherType) {
|
||||||
|
final Intent startProvIntent = new Intent();
|
||||||
|
startProvIntent.putExtra(EXTRA_ADD_TETHER_TYPE, tetherType);
|
||||||
|
startProvIntent.putExtra(EXTRA_RUN_PROVISION, true);
|
||||||
|
startProvIntent.setComponent(TETHER_SERVICE);
|
||||||
|
mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scheduleProvisioningRechecks(int type) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
|
||||||
|
intent.putExtra(EXTRA_SET_ALARM, true);
|
||||||
|
intent.setComponent(TETHER_SERVICE);
|
||||||
|
final long ident = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
mContext.startServiceAsUser(intent, UserHandle.CURRENT);
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(ident);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelTetherProvisioningRechecks(int type) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.putExtra(EXTRA_REM_TETHER_TYPE, type);
|
||||||
|
intent.setComponent(TETHER_SERVICE);
|
||||||
|
final long ident = Binder.clearCallingIdentity();
|
||||||
|
try {
|
||||||
|
mContext.startServiceAsUser(intent, UserHandle.CURRENT);
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(ident);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,19 +17,13 @@
|
|||||||
package com.android.server.connectivity.tethering;
|
package com.android.server.connectivity.tethering;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.INetd;
|
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.net.dhcp.DhcpServer;
|
|
||||||
import android.net.dhcp.DhcpServingParams;
|
|
||||||
import android.net.ip.IpServer;
|
import android.net.ip.IpServer;
|
||||||
import android.net.ip.RouterAdvertisementDaemon;
|
|
||||||
import android.net.util.InterfaceParams;
|
|
||||||
import android.net.util.NetdService;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.net.util.SharedLog;
|
import android.net.util.SharedLog;
|
||||||
import android.os.Looper;
|
import android.os.Handler;
|
||||||
|
|
||||||
import com.android.internal.util.StateMachine;
|
import com.android.internal.util.StateMachine;
|
||||||
|
import com.android.server.connectivity.MockableSystemProperties;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -65,4 +59,9 @@ public class TetheringDependencies {
|
|||||||
public NetworkRequest getDefaultNetworkRequest() {
|
public NetworkRequest getDefaultNetworkRequest() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EntitlementManager getEntitlementManager(Context ctx, SharedLog log,
|
||||||
|
MockableSystemProperties systemProperties) {
|
||||||
|
return new EntitlementManager(ctx, log, systemProperties);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,15 +23,15 @@ import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
|
|||||||
import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
|
import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
|
||||||
import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
|
import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
|
||||||
import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
|
import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
|
||||||
import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
|
|
||||||
import static android.net.ConnectivityManager.TETHERING_WIFI;
|
|
||||||
import static android.net.ConnectivityManager.TETHERING_USB;
|
import static android.net.ConnectivityManager.TETHERING_USB;
|
||||||
|
import static android.net.ConnectivityManager.TETHERING_WIFI;
|
||||||
|
import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
|
||||||
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
import static android.net.ConnectivityManager.TYPE_MOBILE;
|
||||||
import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
|
|
||||||
import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
|
|
||||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
|
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
|
||||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
|
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
|
||||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
|
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
|
||||||
|
import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
|
||||||
|
import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
|
||||||
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
|
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
|
||||||
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
|
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
|
||||||
|
|
||||||
@@ -39,19 +39,18 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.argThat;
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import static org.mockito.ArgumentMatchers.notNull;
|
import static org.mockito.ArgumentMatchers.notNull;
|
||||||
import static org.mockito.Matchers.anyBoolean;
|
|
||||||
import static org.mockito.Matchers.anyInt;
|
import static org.mockito.Matchers.anyInt;
|
||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Matchers.anyString;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.Mockito.any;
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.doThrow;
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@@ -91,9 +90,9 @@ import android.os.INetworkManagementService;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.test.TestLooper;
|
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.os.test.TestLooper;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.support.test.filters.SmallTest;
|
import android.support.test.filters.SmallTest;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
@@ -126,7 +125,6 @@ import java.util.Vector;
|
|||||||
public class TetheringTest {
|
public class TetheringTest {
|
||||||
private static final int IFINDEX_OFFSET = 100;
|
private static final int IFINDEX_OFFSET = 100;
|
||||||
|
|
||||||
private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
|
|
||||||
private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
|
private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
|
||||||
private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0";
|
private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0";
|
||||||
private static final String TEST_USB_IFNAME = "test_rndis0";
|
private static final String TEST_USB_IFNAME = "test_rndis0";
|
||||||
@@ -370,61 +368,6 @@ public class TetheringTest {
|
|||||||
mServiceContext.unregisterReceiver(mBroadcastReceiver);
|
mServiceContext.unregisterReceiver(mBroadcastReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupForRequiredProvisioning() {
|
|
||||||
// Produce some acceptable looking provision app setting if requested.
|
|
||||||
when(mResources.getStringArray(
|
|
||||||
com.android.internal.R.array.config_mobile_hotspot_provision_app))
|
|
||||||
.thenReturn(PROVISIONING_APP_NAME);
|
|
||||||
// Don't disable tethering provisioning unless requested.
|
|
||||||
when(mSystemProperties.getBoolean(eq(Tethering.DISABLE_PROVISIONING_SYSPROP_KEY),
|
|
||||||
anyBoolean())).thenReturn(false);
|
|
||||||
// Act like the CarrierConfigManager is present and ready unless told otherwise.
|
|
||||||
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
|
|
||||||
.thenReturn(mCarrierConfigManager);
|
|
||||||
when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
|
|
||||||
mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void canRequireProvisioning() {
|
|
||||||
setupForRequiredProvisioning();
|
|
||||||
sendConfigurationChanged();
|
|
||||||
assertTrue(mTethering.isTetherProvisioningRequired());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void toleratesCarrierConfigManagerMissing() {
|
|
||||||
setupForRequiredProvisioning();
|
|
||||||
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
|
|
||||||
.thenReturn(null);
|
|
||||||
sendConfigurationChanged();
|
|
||||||
// Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
|
|
||||||
// We therefore still require provisioning.
|
|
||||||
assertTrue(mTethering.isTetherProvisioningRequired());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void toleratesCarrierConfigMissing() {
|
|
||||||
setupForRequiredProvisioning();
|
|
||||||
when(mCarrierConfigManager.getConfig()).thenReturn(null);
|
|
||||||
sendConfigurationChanged();
|
|
||||||
// We still have a provisioning app configured, so still require provisioning.
|
|
||||||
assertTrue(mTethering.isTetherProvisioningRequired());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void provisioningNotRequiredWhenAppNotFound() {
|
|
||||||
setupForRequiredProvisioning();
|
|
||||||
when(mResources.getStringArray(
|
|
||||||
com.android.internal.R.array.config_mobile_hotspot_provision_app))
|
|
||||||
.thenReturn(null);
|
|
||||||
assertTrue(!mTethering.isTetherProvisioningRequired());
|
|
||||||
when(mResources.getStringArray(
|
|
||||||
com.android.internal.R.array.config_mobile_hotspot_provision_app))
|
|
||||||
.thenReturn(new String[] {"malformedApp"});
|
|
||||||
assertTrue(!mTethering.isTetherProvisioningRequired());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendWifiApStateChanged(int state) {
|
private void sendWifiApStateChanged(int state) {
|
||||||
final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
|
final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
|
||||||
intent.putExtra(EXTRA_WIFI_AP_STATE, state);
|
intent.putExtra(EXTRA_WIFI_AP_STATE, state);
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.connectivity.tethering;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.net.util.SharedLog;
|
||||||
|
import android.os.PersistableBundle;
|
||||||
|
import android.support.test.filters.SmallTest;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
import android.telephony.CarrierConfigManager;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
import com.android.server.connectivity.MockableSystemProperties;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
@SmallTest
|
||||||
|
public final class EntitlementManagerTest {
|
||||||
|
|
||||||
|
private static final int EVENT_EM_UPDATE = 1;
|
||||||
|
private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
|
||||||
|
|
||||||
|
@Mock private CarrierConfigManager mCarrierConfigManager;
|
||||||
|
@Mock private Context mContext;
|
||||||
|
@Mock private ContentResolver mContent;
|
||||||
|
@Mock private MockableSystemProperties mSystemProperties;
|
||||||
|
@Mock private Resources mResources;
|
||||||
|
@Mock private SharedLog mLog;
|
||||||
|
|
||||||
|
// Like so many Android system APIs, these cannot be mocked because it is marked final.
|
||||||
|
// We have to use the real versions.
|
||||||
|
private final PersistableBundle mCarrierConfig = new PersistableBundle();
|
||||||
|
|
||||||
|
private EntitlementManager mEnMgr;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
when(mContext.getResources()).thenReturn(mResources);
|
||||||
|
when(mContext.getContentResolver()).thenReturn(mContent);
|
||||||
|
when(mResources.getStringArray(R.array.config_tether_dhcp_range))
|
||||||
|
.thenReturn(new String[0]);
|
||||||
|
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
|
||||||
|
.thenReturn(new String[0]);
|
||||||
|
when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
|
||||||
|
.thenReturn(new String[0]);
|
||||||
|
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
|
||||||
|
.thenReturn(new String[0]);
|
||||||
|
when(mResources.getIntArray(R.array.config_tether_upstream_types))
|
||||||
|
.thenReturn(new int[0]);
|
||||||
|
when(mLog.forSubComponent(anyString())).thenReturn(mLog);
|
||||||
|
|
||||||
|
mEnMgr = new EntitlementManager(mContext, mLog, mSystemProperties);
|
||||||
|
mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {}
|
||||||
|
|
||||||
|
private void setupForRequiredProvisioning() {
|
||||||
|
// Produce some acceptable looking provision app setting if requested.
|
||||||
|
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
|
||||||
|
.thenReturn(PROVISIONING_APP_NAME);
|
||||||
|
// Don't disable tethering provisioning unless requested.
|
||||||
|
when(mSystemProperties.getBoolean(eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY),
|
||||||
|
anyBoolean())).thenReturn(false);
|
||||||
|
// Act like the CarrierConfigManager is present and ready unless told otherwise.
|
||||||
|
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
|
||||||
|
.thenReturn(mCarrierConfigManager);
|
||||||
|
when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
|
||||||
|
mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void canRequireProvisioning() {
|
||||||
|
setupForRequiredProvisioning();
|
||||||
|
mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
|
||||||
|
assertTrue(mEnMgr.isTetherProvisioningRequired());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toleratesCarrierConfigManagerMissing() {
|
||||||
|
setupForRequiredProvisioning();
|
||||||
|
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
|
||||||
|
.thenReturn(null);
|
||||||
|
mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
|
||||||
|
// Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
|
||||||
|
// Therefore provisioning still be required.
|
||||||
|
assertTrue(mEnMgr.isTetherProvisioningRequired());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toleratesCarrierConfigMissing() {
|
||||||
|
setupForRequiredProvisioning();
|
||||||
|
when(mCarrierConfigManager.getConfig()).thenReturn(null);
|
||||||
|
mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
|
||||||
|
// We still have a provisioning app configured, so still require provisioning.
|
||||||
|
assertTrue(mEnMgr.isTetherProvisioningRequired());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void provisioningNotRequiredWhenAppNotFound() {
|
||||||
|
setupForRequiredProvisioning();
|
||||||
|
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
|
||||||
|
.thenReturn(null);
|
||||||
|
mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
|
||||||
|
assertFalse(mEnMgr.isTetherProvisioningRequired());
|
||||||
|
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
|
||||||
|
.thenReturn(new String[] {"malformedApp"});
|
||||||
|
mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
|
||||||
|
assertFalse(mEnMgr.isTetherProvisioningRequired());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user