Merge "Use unstable networkstack AIDLs in development branches"
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
index fd6f171..f14def6 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
@@ -37,8 +37,8 @@
private TetheringConstants() { }
/**
- * Extra used for communicating with the TetherService. Includes the type of tethering to
- * enable if any.
+ * Extra used for communicating with the TetherService and TetherProvisioningActivity.
+ * Includes the type of tethering to enable if any.
*/
public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
/**
@@ -56,8 +56,38 @@
*/
public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
/**
- * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
- * which will receive provisioning results. Can be left empty.
+ * Extra used for communicating with the TetherService and TetherProvisioningActivity.
+ * Contains the {@link ResultReceiver} which will receive provisioning results.
+ * Can not be empty.
*/
public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+
+ /**
+ * Extra used for communicating with the TetherService and TetherProvisioningActivity.
+ * Contains the subId of current active cellular upstream.
+ * @hide
+ */
+ public static final String EXTRA_TETHER_SUBID = "android.net.extra.TETHER_SUBID";
+
+ /**
+ * Extra used for telling TetherProvisioningActivity the entitlement package name and class
+ * name to start UI entitlement check.
+ * @hide
+ */
+ public static final String EXTRA_TETHER_UI_PROVISIONING_APP_NAME =
+ "android.net.extra.TETHER_UI_PROVISIONING_APP_NAME";
+
+ /**
+ * Extra used for telling TetherService the intent action to start silent entitlement check.
+ * @hide
+ */
+ public static final String EXTRA_TETHER_SILENT_PROVISIONING_ACTION =
+ "android.net.extra.TETHER_SILENT_PROVISIONING_ACTION";
+
+ /**
+ * Extra used for TetherService to receive the response of provisioning check.
+ * @hide
+ */
+ public static final String EXTRA_TETHER_PROVISIONING_RESPONSE =
+ "android.net.extra.TETHER_PROVISIONING_RESPONSE";
}
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 04ca033..87e5c1e 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -171,6 +171,14 @@
*/
public static final int TETHERING_ETHERNET = 5;
+ /**
+ * WIGIG tethering type. Use a separate type to prevent
+ * conflicts with TETHERING_WIFI
+ * This type is only used internally by the tethering module
+ * @hide
+ */
+ public static final int TETHERING_WIGIG = 6;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
diff --git a/Tethering/jarjar-rules.txt b/Tethering/jarjar-rules.txt
index e90a2cc..8f072e4 100644
--- a/Tethering/jarjar-rules.txt
+++ b/Tethering/jarjar-rules.txt
@@ -15,3 +15,6 @@
rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1
rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1
+
+# Classes from net-utils-framework-common
+rule com.android.net.module.util.** com.android.networkstack.tethering.util.@1
\ No newline at end of file
diff --git a/Tethering/jni/android_net_util_TetheringUtils.cpp b/Tethering/jni/android_net_util_TetheringUtils.cpp
index 5493440..f6eb40a 100644
--- a/Tethering/jni/android_net_util_TetheringUtils.cpp
+++ b/Tethering/jni/android_net_util_TetheringUtils.cpp
@@ -18,6 +18,7 @@
#include <error.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIHelpCompat.h>
#include <nativehelper/ScopedUtfChars.h>
#include <net/if.h>
#include <netinet/icmp6.h>
diff --git a/Tethering/res/values/config.xml b/Tethering/res/values/config.xml
index 3f5bc90..4807e52 100644
--- a/Tethering/res/values/config.xml
+++ b/Tethering/res/values/config.xml
@@ -43,6 +43,13 @@
</string-array>
<!-- List of regexpressions describing the interface (if any) that represent tetherable
+ WiGig interfaces. If the device doesn't want to support tethering over WiGig this
+ should be empty. An example would be "wigig\\d" -->
+ <string-array translatable="false" name="config_tether_wigig_regexs">
+ <item>"wigig\\d"</item>
+ </string-array>
+
+ <!-- List of regexpressions describing the interface (if any) that represent tetherable
Wifi P2P interfaces. If the device doesn't want to support tethering over Wifi P2p this
should be empty. An example would be "p2p-p2p.*" -->
<string-array translatable="false" name="config_tether_wifi_p2p_regexs">
diff --git a/Tethering/res/values/overlayable.xml b/Tethering/res/values/overlayable.xml
index 4e2bb1e..6a33d55 100644
--- a/Tethering/res/values/overlayable.xml
+++ b/Tethering/res/values/overlayable.xml
@@ -20,6 +20,7 @@
<item type="array" name="config_tether_usb_regexs"/>
<item type="array" name="config_tether_ncm_regexs" />
<item type="array" name="config_tether_wifi_regexs"/>
+ <item type="array" name="config_tether_wigig_regexs"/>
<item type="array" name="config_tether_wifi_p2p_regexs"/>
<item type="array" name="config_tether_bluetooth_regexs"/>
<item type="array" name="config_tether_dhcp_range"/>
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index 2871e7f..a61fcfb 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -615,8 +615,10 @@
final Boolean setIfaceUp;
if (mInterfaceType == TetheringManager.TETHERING_WIFI
- || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
- // The WiFi stack has ownership of the interface up/down state.
+ || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P
+ || mInterfaceType == TetheringManager.TETHERING_ETHERNET
+ || mInterfaceType == TetheringManager.TETHERING_WIGIG) {
+ // The WiFi and Ethernet stack has ownership of the interface up/down state.
// It is unclear whether the Bluetooth or USB stacks will manage their own
// state.
setIfaceUp = null;
diff --git a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
index 3c6e8d8..9dace70 100644
--- a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -19,6 +19,10 @@
import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
+import static android.net.TetheringConstants.EXTRA_TETHER_PROVISIONING_RESPONSE;
+import static android.net.TetheringConstants.EXTRA_TETHER_SILENT_PROVISIONING_ACTION;
+import static android.net.TetheringConstants.EXTRA_TETHER_SUBID;
+import static android.net.TetheringConstants.EXTRA_TETHER_UI_PROVISIONING_APP_NAME;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringManager.TETHERING_INVALID;
@@ -69,7 +73,6 @@
protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
private static final String ACTION_PROVISIONING_ALARM =
"com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM";
- private static final String EXTRA_SUBID = "subId";
private final ComponentName mSilentProvisioningService;
private static final int MS_PER_HOUR = 60 * 60 * 1000;
@@ -197,9 +200,9 @@
// till upstream change to cellular.
if (mUsingCellularAsUpstream) {
if (showProvisioningUi) {
- runUiTetherProvisioning(downstreamType, config.activeDataSubId);
+ runUiTetherProvisioning(downstreamType, config);
} else {
- runSilentTetherProvisioning(downstreamType, config.activeDataSubId);
+ runSilentTetherProvisioning(downstreamType, config);
}
mNeedReRunProvisioningUi = false;
} else {
@@ -262,9 +265,9 @@
if (mCurrentEntitlementResults.indexOfKey(downstream) < 0) {
if (mNeedReRunProvisioningUi) {
mNeedReRunProvisioningUi = false;
- runUiTetherProvisioning(downstream, config.activeDataSubId);
+ runUiTetherProvisioning(downstream, config);
} else {
- runSilentTetherProvisioning(downstream, config.activeDataSubId);
+ runSilentTetherProvisioning(downstream, config);
}
}
}
@@ -361,7 +364,7 @@
* @param subId default data subscription ID.
*/
@VisibleForTesting
- protected void runSilentTetherProvisioning(int type, int subId) {
+ protected Intent runSilentTetherProvisioning(int type, final TetheringConfiguration config) {
if (DBG) mLog.i("runSilentTetherProvisioning: " + type);
// For silent provisioning, settings would stop tethering when entitlement fail.
ResultReceiver receiver = buildProxyReceiver(type, false/* notifyFail */, null);
@@ -369,17 +372,20 @@
Intent intent = new Intent();
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
intent.putExtra(EXTRA_RUN_PROVISION, true);
+ intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, config.provisioningAppNoUi);
+ intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, config.provisioningResponse);
intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
- intent.putExtra(EXTRA_SUBID, subId);
+ intent.putExtra(EXTRA_TETHER_SUBID, config.activeDataSubId);
intent.setComponent(mSilentProvisioningService);
// Only admin user can change tethering and SilentTetherProvisioning don't need to
// show UI, it is fine to always start setting's background service as system user.
mContext.startService(intent);
+ return intent;
}
- private void runUiTetherProvisioning(int type, int subId) {
+ private void runUiTetherProvisioning(int type, final TetheringConfiguration config) {
ResultReceiver receiver = buildProxyReceiver(type, true/* notifyFail */, null);
- runUiTetherProvisioning(type, subId, receiver);
+ runUiTetherProvisioning(type, config, receiver);
}
/**
@@ -389,17 +395,20 @@
* @param receiver to receive entitlement check result.
*/
@VisibleForTesting
- protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) {
+ protected Intent runUiTetherProvisioning(int type, final TetheringConfiguration config,
+ ResultReceiver receiver) {
if (DBG) mLog.i("runUiTetherProvisioning: " + type);
Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING_UI);
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, config.provisioningApp);
intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
- intent.putExtra(EXTRA_SUBID, subId);
+ intent.putExtra(EXTRA_TETHER_SUBID, config.activeDataSubId);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Only launch entitlement UI for system user. Entitlement UI should not appear for other
// user because only admin user is allowed to change tethering.
mContext.startActivity(intent);
+ return intent;
}
// Not needed to check if this don't run on the handler thread because it's private.
@@ -631,7 +640,7 @@
receiver.send(cacheValue, null);
} else {
ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
- runUiTetherProvisioning(downstream, config.activeDataSubId, proxy);
+ runUiTetherProvisioning(downstream, config, proxy);
}
}
}
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
index fe92204..33b9d00 100644
--- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
+++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
@@ -16,8 +16,11 @@
package com.android.networkstack.tethering;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
+import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
import static android.net.util.TetheringUtils.uint16;
+import android.annotation.NonNull;
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
@@ -25,6 +28,7 @@
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
import android.net.netlink.NetlinkSocket;
+import android.net.netlink.StructNlMsgHdr;
import android.net.util.SharedLog;
import android.net.util.SocketUtils;
import android.os.Handler;
@@ -37,9 +41,11 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.FileDescriptor;
+import java.io.InterruptedIOException;
import java.io.IOException;
import java.net.SocketAddress;
import java.net.SocketException;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.NoSuchElementException;
@@ -63,6 +69,11 @@
private static final int NF_NETLINK_CONNTRACK_NEW = 1;
private static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
private static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
+ // Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h
+ public static final short NFNL_SUBSYS_CTNETLINK = 1;
+ public static final short IPCTNL_MSG_CT_GET = 1;
+
+ private final long NETLINK_MESSAGE_TIMEOUT_MS = 500;
private final Handler mHandler;
private final SharedLog mLog;
@@ -226,6 +237,9 @@
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
if (h1 == null) return false;
+ sendNetlinkMessage(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
+ (short) (NLM_F_REQUEST | NLM_F_DUMP));
+
final NativeHandle h2 = mDeps.createConntrackSocket(
NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
if (h2 == null) {
@@ -252,6 +266,25 @@
return results.mSuccess;
}
+ @VisibleForTesting
+ public void sendNetlinkMessage(@NonNull NativeHandle handle, short type, short flags) {
+ final int length = StructNlMsgHdr.STRUCT_SIZE;
+ final byte[] msg = new byte[length];
+ final StructNlMsgHdr nlh = new StructNlMsgHdr();
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(msg);
+ nlh.nlmsg_len = length;
+ nlh.nlmsg_type = type;
+ nlh.nlmsg_flags = flags;
+ nlh.nlmsg_seq = 1;
+ nlh.pack(byteBuffer);
+ try {
+ NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length,
+ NETLINK_MESSAGE_TIMEOUT_MS);
+ } catch (ErrnoException | InterruptedIOException e) {
+ mLog.e("Unable to send netfilter message, error: " + e);
+ }
+ }
+
private void closeFdInNativeHandle(final NativeHandle h) {
try {
h.close();
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 71ab176..3627085 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.Manifest.permission.NETWORK_STACK;
+import static android.content.pm.PackageManager.GET_ACTIVITIES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
@@ -39,6 +40,7 @@
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+import static android.net.TetheringManager.TETHERING_WIGIG;
import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
@@ -71,6 +73,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import android.net.EthernetManager;
@@ -110,7 +113,6 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceSpecificException;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -494,7 +496,8 @@
if (up) {
maybeTrackNewInterfaceLocked(iface);
} else {
- if (ifaceNameToType(iface) == TETHERING_BLUETOOTH) {
+ if (ifaceNameToType(iface) == TETHERING_BLUETOOTH
+ || ifaceNameToType(iface) == TETHERING_WIGIG) {
stopTrackingInterfaceLocked(iface);
} else {
// Ignore usb0 down after enabling RNDIS.
@@ -516,6 +519,8 @@
if (cfg.isWifi(iface)) {
return TETHERING_WIFI;
+ } else if (cfg.isWigig(iface)) {
+ return TETHERING_WIGIG;
} else if (cfg.isWifiP2p(iface)) {
return TETHERING_WIFI_P2P;
} else if (cfg.isUsb(iface)) {
@@ -811,11 +816,30 @@
}
}
+ private boolean isProvisioningNeededButUnavailable() {
+ return isTetherProvisioningRequired() && !doesEntitlementPackageExist();
+ }
+
boolean isTetherProvisioningRequired() {
final TetheringConfiguration cfg = mConfig;
return mEntitlementMgr.isTetherProvisioningRequired(cfg);
}
+ private boolean doesEntitlementPackageExist() {
+ // provisioningApp must contain package and class name.
+ if (mConfig.provisioningApp.length != 2) {
+ return false;
+ }
+
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ pm.getPackageInfo(mConfig.provisioningApp[0], GET_ACTIVITIES);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ return true;
+ }
+
// TODO: Figure out how to update for local hotspot mode interfaces.
private void sendTetherStateChangedBroadcast() {
if (!isTetheringSupported()) return;
@@ -2175,14 +2199,14 @@
// gservices could set the secure setting to 1 though to enable it on a build where it
// had previously been turned off.
boolean isTetheringSupported() {
- final int defaultVal =
- SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
+ final int defaultVal = mDeps.isTetheringDenied() ? 0 : 1;
final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
final boolean tetherEnabledInSettings = tetherSupported
&& !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
- return tetherEnabledInSettings && hasTetherableConfiguration();
+ return tetherEnabledInSettings && hasTetherableConfiguration()
+ && !isProvisioningNeededButUnavailable();
}
void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index 1e94de1..e1771a5 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -92,6 +92,7 @@
public final String[] tetherableUsbRegexs;
public final String[] tetherableWifiRegexs;
+ public final String[] tetherableWigigRegexs;
public final String[] tetherableWifiP2pRegexs;
public final String[] tetherableBluetoothRegexs;
public final String[] tetherableNcmRegexs;
@@ -105,6 +106,7 @@
public final String[] provisioningApp;
public final String provisioningAppNoUi;
public final int provisioningCheckPeriod;
+ public final String provisioningResponse;
public final int activeDataSubId;
@@ -124,6 +126,7 @@
// us an interface name. Careful consideration needs to be given to
// implications for Settings and for provisioning checks.
tetherableWifiRegexs = getResourceStringArray(res, R.array.config_tether_wifi_regexs);
+ tetherableWigigRegexs = getResourceStringArray(res, R.array.config_tether_wigig_regexs);
tetherableWifiP2pRegexs = getResourceStringArray(
res, R.array.config_tether_wifi_p2p_regexs);
tetherableBluetoothRegexs = getResourceStringArray(
@@ -141,10 +144,13 @@
enableLegacyDhcpServer = getEnableLegacyDhcpServer(res);
provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app);
- provisioningAppNoUi = getProvisioningAppNoUi(res);
+ provisioningAppNoUi = getResourceString(res,
+ R.string.config_mobile_hotspot_provision_app_no_ui);
provisioningCheckPeriod = getResourceInteger(res,
R.integer.config_mobile_hotspot_provision_check_period,
0 /* No periodic re-check */);
+ provisioningResponse = getResourceString(res,
+ R.string.config_mobile_hotspot_provision_response);
mOffloadPollInterval = getResourceInteger(res,
R.integer.config_tether_offload_poll_interval,
@@ -163,6 +169,11 @@
return matchesDownstreamRegexs(iface, tetherableWifiRegexs);
}
+ /** Check whether input interface belong to wigig.*/
+ public boolean isWigig(String iface) {
+ return matchesDownstreamRegexs(iface, tetherableWigigRegexs);
+ }
+
/** Check whether this interface is Wifi P2P interface. */
public boolean isWifiP2p(String iface) {
return matchesDownstreamRegexs(iface, tetherableWifiP2pRegexs);
@@ -341,9 +352,9 @@
return copy(LEGACY_DHCP_DEFAULT_RANGE);
}
- private static String getProvisioningAppNoUi(Resources res) {
+ private static String getResourceString(Resources res, final int resId) {
try {
- return res.getString(R.string.config_mobile_hotspot_provision_app_no_ui);
+ return res.getString(resId);
} catch (Resources.NotFoundException e) {
return "";
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
index 8f4b964..131a5fb 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
@@ -26,6 +26,8 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.SystemProperties;
+import android.text.TextUtils;
import androidx.annotation.NonNull;
@@ -147,4 +149,11 @@
* Get a reference to BluetoothAdapter to be used by tethering.
*/
public abstract BluetoothAdapter getBluetoothAdapter();
+
+ /**
+ * Get SystemProperties which indicate whether tethering is denied.
+ */
+ public boolean isTetheringDenied() {
+ return TextUtils.equals(SystemProperties.get("ro.tether.denied"), "true");
+ }
}
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 4f88605..05cf58a 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -859,6 +859,7 @@
verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
+ verify(mIpNeighborMonitor).stop();
resetNetdAndBpfCoordinator();
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
index 72fa916..354e753 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
@@ -16,8 +16,16 @@
package com.android.networkstack.tethering;
+import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
+import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
+import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
+import static android.net.TetheringConstants.EXTRA_TETHER_PROVISIONING_RESPONSE;
+import static android.net.TetheringConstants.EXTRA_TETHER_SILENT_PROVISIONING_ACTION;
+import static android.net.TetheringConstants.EXTRA_TETHER_SUBID;
+import static android.net.TetheringConstants.EXTRA_TETHER_UI_PROVISIONING_APP_NAME;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
import static android.net.TetheringManager.TETHERING_ETHERNET;
+import static android.net.TetheringManager.TETHERING_INVALID;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
@@ -44,6 +52,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.net.util.SharedLog;
import android.os.Bundle;
@@ -53,6 +62,7 @@
import android.os.SystemProperties;
import android.os.test.TestLooper;
import android.provider.DeviceConfig;
+import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import androidx.test.filters.SmallTest;
@@ -76,6 +86,7 @@
private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
+ private static final String PROVISIONING_APP_RESPONSE = "app_response";
@Mock private CarrierConfigManager mCarrierConfigManager;
@Mock private Context mContext;
@@ -122,15 +133,51 @@
}
@Override
- protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) {
+ protected Intent runUiTetherProvisioning(int type,
+ final TetheringConfiguration config, final ResultReceiver receiver) {
+ Intent intent = super.runUiTetherProvisioning(type, config, receiver);
+ assertUiTetherProvisioningIntent(type, config, receiver, intent);
uiProvisionCount++;
receiver.send(fakeEntitlementResult, null);
+ return intent;
+ }
+
+ private void assertUiTetherProvisioningIntent(int type, final TetheringConfiguration config,
+ final ResultReceiver receiver, final Intent intent) {
+ assertEquals(Settings.ACTION_TETHER_PROVISIONING_UI, intent.getAction());
+ assertEquals(type, intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID));
+ final String[] appName = intent.getStringArrayExtra(
+ EXTRA_TETHER_UI_PROVISIONING_APP_NAME);
+ assertEquals(PROVISIONING_APP_NAME.length, appName.length);
+ for (int i = 0; i < PROVISIONING_APP_NAME.length; i++) {
+ assertEquals(PROVISIONING_APP_NAME[i], appName[i]);
+ }
+ assertEquals(receiver, intent.getParcelableExtra(EXTRA_PROVISION_CALLBACK));
+ assertEquals(config.activeDataSubId,
+ intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID));
}
@Override
- protected void runSilentTetherProvisioning(int type, int subId) {
+ protected Intent runSilentTetherProvisioning(int type,
+ final TetheringConfiguration config) {
+ Intent intent = super.runSilentTetherProvisioning(type, config);
+ assertSilentTetherProvisioning(type, config, intent);
silentProvisionCount++;
addDownstreamMapping(type, fakeEntitlementResult);
+ return intent;
+ }
+
+ private void assertSilentTetherProvisioning(int type, final TetheringConfiguration config,
+ final Intent intent) {
+ assertEquals(type, intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID));
+ assertEquals(true, intent.getBooleanExtra(EXTRA_RUN_PROVISION, false));
+ assertEquals(PROVISIONING_NO_UI_APP_NAME,
+ intent.getStringExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION));
+ assertEquals(PROVISIONING_APP_RESPONSE,
+ intent.getStringExtra(EXTRA_TETHER_PROVISIONING_RESPONSE));
+ assertTrue(intent.hasExtra(EXTRA_PROVISION_CALLBACK));
+ assertEquals(config.activeDataSubId,
+ intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID));
}
}
@@ -187,6 +234,8 @@
.thenReturn(PROVISIONING_APP_NAME);
when(mResources.getString(R.string.config_mobile_hotspot_provision_app_no_ui))
.thenReturn(PROVISIONING_NO_UI_APP_NAME);
+ when(mResources.getString(R.string.config_mobile_hotspot_provision_response)).thenReturn(
+ PROVISIONING_APP_RESPONSE);
// Act like the CarrierConfigManager is present and ready unless told otherwise.
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
.thenReturn(mCarrierConfigManager);
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
index f8ff1cb..c543fad 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
@@ -17,13 +17,17 @@
package com.android.networkstack.tethering;
import static android.net.util.TetheringUtils.uint16;
+import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.AF_UNIX;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
@@ -31,11 +35,14 @@
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
+import android.net.netlink.StructNlMsgHdr;
import android.net.util.SharedLog;
import android.os.Handler;
import android.os.NativeHandle;
import android.os.test.TestLooper;
+import android.system.ErrnoException;
import android.system.OsConstants;
+import android.system.Os;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -47,6 +54,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.FileDescriptor;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
@RunWith(AndroidJUnit4.class)
@@ -64,6 +74,10 @@
@Mock private IOffloadControl mIOffloadControl;
@Mock private NativeHandle mNativeHandle;
+ // Random values to test Netlink message.
+ private static final short TEST_TYPE = 184;
+ private static final short TEST_FLAGS = 263;
+
class MyDependencies extends OffloadHardwareInterface.Dependencies {
MyDependencies(SharedLog log) {
super(log);
@@ -203,6 +217,31 @@
eq(uint16(udpParams.dst.port)));
}
+ @Test
+ public void testNetlinkMessage() throws Exception {
+ FileDescriptor writeSocket = new FileDescriptor();
+ FileDescriptor readSocket = new FileDescriptor();
+ try {
+ Os.socketpair(AF_UNIX, SOCK_STREAM, 0, writeSocket, readSocket);
+ } catch (ErrnoException e) {
+ fail();
+ return;
+ }
+ when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket);
+
+ mOffloadHw.sendNetlinkMessage(mNativeHandle, TEST_TYPE, TEST_FLAGS);
+
+ ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE);
+ int read = Os.read(readSocket, buffer);
+
+ buffer.flip();
+ assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt());
+ assertEquals(TEST_TYPE, buffer.getShort());
+ assertEquals(TEST_FLAGS, buffer.getShort());
+ assertEquals(1 /* seq */, buffer.getInt());
+ assertEquals(0 /* pid */, buffer.getInt());
+ }
+
private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
final NatTimeoutUpdate params = new NatTimeoutUpdate();
params.proto = proto;
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index 3f4cfe7..a9ac4e2 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -61,6 +61,8 @@
private final SharedLog mLog = new SharedLog("TetheringConfigurationTest");
private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
+ private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
+ private static final String PROVISIONING_APP_RESPONSE = "app_response";
@Mock private Context mContext;
@Mock private TelephonyManager mTelephonyManager;
@Mock private Resources mResources;
@@ -388,6 +390,8 @@
new MockTetheringConfiguration(mMockContext, mLog, anyValidSubId);
assertEquals(mockCfg.provisioningApp[0], PROVISIONING_APP_NAME[0]);
assertEquals(mockCfg.provisioningApp[1], PROVISIONING_APP_NAME[1]);
+ assertEquals(mockCfg.provisioningAppNoUi, PROVISIONING_NO_UI_APP_NAME);
+ assertEquals(mockCfg.provisioningResponse, PROVISIONING_APP_RESPONSE);
}
private void setUpResourceForSubId() {
@@ -403,6 +407,10 @@
new int[0]);
when(mResourcesForSubId.getStringArray(
R.array.config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME);
+ when(mResourcesForSubId.getString(R.string.config_mobile_hotspot_provision_app_no_ui))
+ .thenReturn(PROVISIONING_NO_UI_APP_NAME);
+ when(mResourcesForSubId.getString(
+ R.string.config_mobile_hotspot_provision_response)).thenReturn(
+ PROVISIONING_APP_RESPONSE);
}
-
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 2b2dfae..d37aad2 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -16,6 +16,7 @@
package com.android.networkstack.tethering;
+import static android.content.pm.PackageManager.GET_ACTIVITIES;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM;
@@ -81,6 +82,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
@@ -204,6 +206,7 @@
@Mock private EthernetManager mEm;
@Mock private TetheringNotificationUpdater mNotificationUpdater;
@Mock private BpfCoordinator mBpfCoordinator;
+ @Mock private PackageManager mPackageManager;
private final MockIpServerDependencies mIpServerDependencies =
spy(new MockIpServerDependencies());
@@ -264,6 +267,11 @@
}
@Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+
+ @Override
public String getSystemServiceName(Class<?> serviceClass) {
if (TelephonyManager.class.equals(serviceClass)) return Context.TELEPHONY_SERVICE;
return super.getSystemServiceName(serviceClass);
@@ -425,6 +433,11 @@
public TetheringNotificationUpdater getNotificationUpdater(Context ctx, Looper looper) {
return mNotificationUpdater;
}
+
+ @Override
+ public boolean isTetheringDenied() {
+ return false;
+ }
}
private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4,
@@ -1951,6 +1964,23 @@
assertEquals(TETHER_ERROR_IFACE_CFG_ERROR, mTethering.getLastTetherError(TEST_ETH_IFNAME));
}
+ @Test
+ public void testProvisioningNeededButUnavailable() throws Exception {
+ assertTrue(mTethering.isTetheringSupported());
+ verify(mPackageManager, never()).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES);
+
+ setupForRequiredProvisioning();
+ assertTrue(mTethering.isTetheringSupported());
+ verify(mPackageManager).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES);
+ reset(mPackageManager);
+
+ doThrow(PackageManager.NameNotFoundException.class).when(mPackageManager).getPackageInfo(
+ PROVISIONING_APP_NAME[0], GET_ACTIVITIES);
+ setupForRequiredProvisioning();
+ assertFalse(mTethering.isTetheringSupported());
+ verify(mPackageManager).getPackageInfo(PROVISIONING_APP_NAME[0], GET_ACTIVITIES);
+ }
+
// TODO: Test that a request for hotspot mode doesn't interfere with an
// already operating tethering mode interface.
}