Merge "Fix usage of annotations in TetheringLib"
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 1083adb..fa3926c 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -29,6 +29,7 @@
"netd_aidl_interface-unstable-java",
"netlink-client",
"networkstack-aidl-interfaces-unstable-java",
+ "android.hardware.tetheroffload.config-V1.0-java",
"android.hardware.tetheroffload.control-V1.0-java",
"net-utils-framework-common",
],
@@ -51,26 +52,26 @@
// Due to b/143733063, APK can't access a jni lib that is in APEX (but not in the APK).
cc_library {
name: "libtetherutilsjni",
+ sdk_version: "current",
srcs: [
"jni/android_net_util_TetheringUtils.cpp",
],
shared_libs: [
- "libcgrouprc",
- "libnativehelper_compat_libc++",
- "libvndksupport",
- ],
- static_libs: [
- "android.hardware.tetheroffload.config@1.0",
"liblog",
- "libbase",
- "libbinderthreadstate",
- "libcutils",
- "libhidlbase",
- "libjsoncpp",
- "libprocessgroup",
- "libutils",
+ "libnativehelper_compat_libc++",
],
+ // We cannot use plain "libc++" here to link libc++ dynamically because it results in:
+ // java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found
+ // even if "libc++" is added into jni_libs below. Adding "libc++_shared" into jni_libs doesn't
+ // build because soong complains of:
+ // module Tethering missing dependencies: libc++_shared
+ //
+ // So, link libc++ statically. This means that we also need to ensure that all the C++ libraries
+ // we depend on do not dynamically link libc++. This is currently the case, because liblog is
+ // C-only and libnativehelper_compat_libc also uses stl: "c++_static".
+ stl: "c++_static",
+
cflags: [
"-Wall",
"-Werror",
@@ -90,9 +91,8 @@
// Build system doesn't track transitive dependeicies for jni_libs, list all the dependencies
// explicitly.
jni_libs: [
- "libcgrouprc",
+ "liblog",
"libnativehelper_compat_libc++",
- "libvndksupport",
"libtetherutilsjni",
],
resource_dirs: [
diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp
index 24762ff..cb0de7a 100644
--- a/Tethering/common/TetheringLib/Android.bp
+++ b/Tethering/common/TetheringLib/Android.bp
@@ -60,16 +60,33 @@
],
hostdex: true, // for hiddenapi check
- visibility: [
- "//frameworks/base/packages/Tethering:__subpackages__",
- //TODO(b/147200698) remove below lines when the platform is built with stubs
- "//frameworks/base",
- "//frameworks/base/services",
- "//frameworks/base/services/core",
- ],
+ visibility: ["//frameworks/base/packages/Tethering:__subpackages__"],
apex_available: ["com.android.tethering"],
}
+droidstubs {
+ name: "framework-tethering-stubs-sources",
+ defaults: ["framework-module-stubs-defaults-module_libs_api"],
+ srcs: [
+ "src/android/net/TetheredClient.java",
+ "src/android/net/TetheringManager.java",
+ "src/android/net/TetheringConstants.java",
+ ],
+ libs: [
+ "tethering-aidl-interfaces-java",
+ "framework-all",
+ ],
+ sdk_version: "core_platform",
+}
+
+java_library {
+ name: "framework-tethering-stubs",
+ srcs: [":framework-tethering-stubs-sources"],
+ libs: ["framework-all"],
+ static_libs: ["tethering-aidl-interfaces-java"],
+ sdk_version: "core_platform",
+}
+
filegroup {
name: "framework-tethering-srcs",
srcs: [
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
index 6514688..779aa3b 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -25,7 +27,7 @@
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
@@ -34,6 +36,7 @@
* @hide
*/
@SystemApi
+@SystemApi(client = MODULE_LIBRARIES)
@TestApi
public final class TetheredClient implements Parcelable {
@NonNull
@@ -83,7 +86,7 @@
* @hide
*/
public TetheredClient addAddresses(@NonNull TetheredClient other) {
- final HashSet<AddressInfo> newAddresses = new HashSet<>(
+ final LinkedHashSet<AddressInfo> newAddresses = new LinkedHashSet<>(
mAddresses.size() + other.mAddresses.size());
newAddresses.addAll(mAddresses);
newAddresses.addAll(other.mAddresses);
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
index 00cf98e..df87ac9 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
@@ -16,6 +16,9 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
+import android.annotation.SystemApi;
import android.os.ResultReceiver;
/**
@@ -28,39 +31,30 @@
* symbols from framework-tethering even when they are in a non-hidden class.
* @hide
*/
+@SystemApi(client = MODULE_LIBRARIES)
public class TetheringConstants {
/**
* Extra used for communicating with the TetherService. Includes the type of tethering to
* enable if any.
- *
- * {@hide}
*/
public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
/**
* Extra used for communicating with the TetherService. Includes the type of tethering for
* which to cancel provisioning.
- *
- * {@hide}
*/
public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
/**
* Extra used for communicating with the TetherService. True to schedule a recheck of tether
* provisioning.
- *
- * {@hide}
*/
public static final String EXTRA_SET_ALARM = "extraSetAlarm";
/**
* Tells the TetherService to run a provision check now.
- *
- * {@hide}
*/
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.
- *
- * {@hide}
*/
public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
}
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 53a358f..6a9f010 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -15,6 +15,8 @@
*/
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -50,6 +52,7 @@
* @hide
*/
@SystemApi
+@SystemApi(client = MODULE_LIBRARIES)
@TestApi
public class TetheringManager {
private static final String TAG = TetheringManager.class.getSimpleName();
@@ -177,6 +180,7 @@
* service is not connected.
* {@hide}
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public TetheringManager(@NonNull final Context context,
@NonNull Supplier<IBinder> connectorSupplier) {
mContext = context;
@@ -395,6 +399,7 @@
* {@hide}
*/
@Deprecated
+ @SystemApi(client = MODULE_LIBRARIES)
public int tether(@NonNull final String iface) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "tether caller:" + callerPkg);
@@ -418,6 +423,7 @@
* {@hide}
*/
@Deprecated
+ @SystemApi(client = MODULE_LIBRARIES)
public int untether(@NonNull final String iface) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "untether caller:" + callerPkg);
@@ -444,6 +450,7 @@
* {@hide}
*/
@Deprecated
+ @SystemApi(client = MODULE_LIBRARIES)
public int setUsbTethering(final boolean enable) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "setUsbTethering caller:" + callerPkg);
@@ -702,6 +709,7 @@
* {@hide}
*/
// TODO: improve the usage of ResultReceiver, b/145096122
+ @SystemApi(client = MODULE_LIBRARIES)
public void requestLatestTetheringEntitlementResult(final int type,
@NonNull final ResultReceiver receiver, final boolean showEntitlementUi) {
final String callerPkg = mContext.getOpPackageName();
@@ -982,6 +990,7 @@
* interface
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public int getLastTetherError(@NonNull final String iface) {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR;
@@ -1004,6 +1013,7 @@
* what interfaces are considered tetherable usb interfaces.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetherableUsbRegexs() {
mCallback.waitForStarted();
return mTetheringConfiguration.tetherableUsbRegexs;
@@ -1018,6 +1028,7 @@
* what interfaces are considered tetherable wifi interfaces.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetherableWifiRegexs() {
mCallback.waitForStarted();
return mTetheringConfiguration.tetherableWifiRegexs;
@@ -1032,6 +1043,7 @@
* what interfaces are considered tetherable bluetooth interfaces.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetherableBluetoothRegexs() {
mCallback.waitForStarted();
return mTetheringConfiguration.tetherableBluetoothRegexs;
@@ -1044,6 +1056,7 @@
* @return an array of 0 or more Strings of tetherable interface names.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetherableIfaces() {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return new String[0];
@@ -1057,6 +1070,7 @@
* @return an array of 0 or more String of currently tethered interface names.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetheredIfaces() {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return new String[0];
@@ -1076,6 +1090,7 @@
* which failed to tether.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public @NonNull String[] getTetheringErroredIfaces() {
mCallback.waitForStarted();
if (mTetherStatesParcel == null) return new String[0];
@@ -1103,6 +1118,7 @@
* @return a boolean - {@code true} indicating Tethering is supported.
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public boolean isTetheringSupported() {
final String callerPkg = mContext.getOpPackageName();
diff --git a/Tethering/jni/android_net_util_TetheringUtils.cpp b/Tethering/jni/android_net_util_TetheringUtils.cpp
index 1cf8f98..5493440 100644
--- a/Tethering/jni/android_net_util_TetheringUtils.cpp
+++ b/Tethering/jni/android_net_util_TetheringUtils.cpp
@@ -16,123 +16,18 @@
#include <errno.h>
#include <error.h>
-#include <hidl/HidlSupport.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netlink.h>
#include <net/if.h>
#include <netinet/icmp6.h>
#include <sys/socket.h>
-#include <android-base/unique_fd.h>
-#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
#define LOG_TAG "TetheringUtils"
-#include <utils/Log.h>
+#include <android/log.h>
namespace android {
-using hardware::hidl_handle;
-using hardware::hidl_string;
-using hardware::tetheroffload::config::V1_0::IOffloadConfig;
-
-namespace {
-
-inline const sockaddr * asSockaddr(const sockaddr_nl *nladdr) {
- return reinterpret_cast<const sockaddr *>(nladdr);
-}
-
-int conntrackSocket(unsigned groups) {
- base::unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER));
- if (s.get() < 0) return -errno;
-
- const struct sockaddr_nl bind_addr = {
- .nl_family = AF_NETLINK,
- .nl_pad = 0,
- .nl_pid = 0,
- .nl_groups = groups,
- };
- if (bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) != 0) {
- return -errno;
- }
-
- const struct sockaddr_nl kernel_addr = {
- .nl_family = AF_NETLINK,
- .nl_pad = 0,
- .nl_pid = 0,
- .nl_groups = groups,
- };
- if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) {
- return -errno;
- }
-
- return s.release();
-}
-
-// Return a hidl_handle that owns the file descriptor owned by fd, and will
-// auto-close it (otherwise there would be double-close problems).
-//
-// Rely upon the compiler to eliminate the constexprs used for clarity.
-hidl_handle handleFromFileDescriptor(base::unique_fd fd) {
- hidl_handle h;
-
- static constexpr int kNumFds = 1;
- static constexpr int kNumInts = 0;
- native_handle_t *nh = native_handle_create(kNumFds, kNumInts);
- nh->data[0] = fd.release();
-
- static constexpr bool kTakeOwnership = true;
- h.setTo(nh, kTakeOwnership);
-
- return h;
-}
-
-} // namespace
-
-static jboolean android_net_util_configOffload(
- JNIEnv* /* env */) {
- sp<IOffloadConfig> configInterface = IOffloadConfig::getService();
- if (configInterface.get() == nullptr) {
- ALOGD("Could not find IOffloadConfig service.");
- return false;
- }
-
- // Per the IConfigOffload definition:
- //
- // fd1 A file descriptor bound to the following netlink groups
- // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY).
- //
- // fd2 A file descriptor bound to the following netlink groups
- // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
- base::unique_fd
- fd1(conntrackSocket(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY)),
- fd2(conntrackSocket(NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY));
- if (fd1.get() < 0 || fd2.get() < 0) {
- ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
- return false;
- }
-
- hidl_handle h1(handleFromFileDescriptor(std::move(fd1))),
- h2(handleFromFileDescriptor(std::move(fd2)));
-
- bool rval(false);
- hidl_string msg;
- const auto status = configInterface->setHandles(h1, h2,
- [&rval, &msg](bool success, const hidl_string& errMsg) {
- rval = success;
- msg = errMsg;
- });
- if (!status.isOk() || !rval) {
- ALOGE("IOffloadConfig::setHandles() error: '%s' / '%s'",
- status.description().c_str(), msg.c_str());
- // If status is somehow not ok, make sure rval captures this too.
- rval = false;
- }
-
- return rval;
-}
-
static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
jint ifIndex)
{
@@ -229,7 +124,6 @@
*/
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "configOffload", "()Z", (void*) android_net_util_configOffload },
{ "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_util_setupRaSocket },
};
@@ -242,7 +136,7 @@
extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
JNIEnv *env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
- ALOGE("ERROR: GetEnv failed");
+ __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed");
return JNI_ERR;
}
diff --git a/Tethering/src/android/net/util/TetheringUtils.java b/Tethering/src/android/net/util/TetheringUtils.java
index fa543bd..5a6d5c1 100644
--- a/Tethering/src/android/net/util/TetheringUtils.java
+++ b/Tethering/src/android/net/util/TetheringUtils.java
@@ -24,14 +24,6 @@
* {@hide}
*/
public class TetheringUtils {
-
- /**
- * Offload management process need to know conntrack rules to support NAT, but it may not have
- * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and
- * share them with offload management process.
- */
- public static native boolean configOffload();
-
/**
* Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
* @param fd the socket's {@link FileDescriptor}.
diff --git a/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 90b9d3f..b545717 100644
--- a/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -18,19 +18,28 @@
import static android.net.util.TetheringUtils.uint16;
+import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
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.NetlinkSocket;
import android.net.util.SharedLog;
-import android.net.util.TetheringUtils;
+import android.net.util.SocketUtils;
import android.os.Handler;
+import android.os.NativeHandle;
import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.system.Os;
import android.system.OsConstants;
import com.android.internal.annotations.VisibleForTesting;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.SocketAddress;
+import java.net.SocketException;
import java.util.ArrayList;
@@ -49,6 +58,10 @@
private static final String NO_INTERFACE_NAME = "";
private static final String NO_IPV4_ADDRESS = "";
private static final String NO_IPV4_GATEWAY = "";
+ // Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h
+ 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;
private final Handler mHandler;
private final SharedLog mLog;
@@ -121,9 +134,103 @@
return DEFAULT_TETHER_OFFLOAD_DISABLED;
}
- /** Configure offload management process. */
+ /**
+ * Offload management process need to know conntrack rules to support NAT, but it may not have
+ * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and
+ * share them with offload management process.
+ */
public boolean initOffloadConfig() {
- return TetheringUtils.configOffload();
+ IOffloadConfig offloadConfig;
+ try {
+ offloadConfig = IOffloadConfig.getService();
+ } catch (RemoteException e) {
+ mLog.e("getIOffloadConfig error " + e);
+ return false;
+ }
+ if (offloadConfig == null) {
+ mLog.e("Could not find IOffloadConfig service");
+ return false;
+ }
+ // Per the IConfigOffload definition:
+ //
+ // h1 provides a file descriptor bound to the following netlink groups
+ // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY).
+ //
+ // h2 provides a file descriptor bound to the following netlink groups
+ // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
+ final NativeHandle h1 = createConntrackSocket(
+ NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
+ if (h1 == null) return false;
+
+ final NativeHandle h2 = createConntrackSocket(
+ NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
+ if (h2 == null) {
+ closeFdInNativeHandle(h1);
+ return false;
+ }
+
+ final CbResults results = new CbResults();
+ try {
+ offloadConfig.setHandles(h1, h2,
+ (boolean success, String errMsg) -> {
+ results.mSuccess = success;
+ results.mErrMsg = errMsg;
+ });
+ } catch (RemoteException e) {
+ record("initOffloadConfig, setHandles fail", e);
+ return false;
+ }
+ // Explicitly close FDs.
+ closeFdInNativeHandle(h1);
+ closeFdInNativeHandle(h2);
+
+ record("initOffloadConfig, setHandles results:", results);
+ return results.mSuccess;
+ }
+
+ private void closeFdInNativeHandle(final NativeHandle h) {
+ try {
+ h.close();
+ } catch (IOException | IllegalStateException e) {
+ // IllegalStateException means fd is already closed, do nothing here.
+ // Also nothing we can do if IOException.
+ }
+ }
+
+ private NativeHandle createConntrackSocket(final int groups) {
+ FileDescriptor fd;
+ try {
+ fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER);
+ } catch (ErrnoException e) {
+ mLog.e("Unable to create conntrack socket " + e);
+ return null;
+ }
+
+ final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups);
+ try {
+ Os.bind(fd, sockAddr);
+ } catch (ErrnoException | SocketException e) {
+ mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e);
+ try {
+ SocketUtils.closeSocket(fd);
+ } catch (IOException ie) {
+ // Nothing we can do here
+ }
+ return null;
+ }
+ try {
+ Os.connect(fd, sockAddr);
+ } catch (ErrnoException | SocketException e) {
+ mLog.e("connect to kernel fail for groups " + groups + " error: " + e);
+ try {
+ SocketUtils.closeSocket(fd);
+ } catch (IOException ie) {
+ // Nothing we can do here
+ }
+ return null;
+ }
+
+ return new NativeHandle(fd, true);
}
/** Initialize the tethering offload HAL. */
diff --git a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 07abe1a..64c16e4 100644
--- a/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -272,13 +272,6 @@
mStateReceiver = new StateReceiver();
- mNetdCallback = new NetdCallback();
- try {
- mNetd.registerUnsolicitedEventListener(mNetdCallback);
- } catch (RemoteException e) {
- mLog.e("Unable to register netd UnsolicitedEventListener");
- }
-
final UserManager userManager = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
@@ -287,6 +280,14 @@
// Load tethering configuration.
updateConfiguration();
+ // NetdCallback should be registered after updateConfiguration() to ensure
+ // TetheringConfiguration is created.
+ mNetdCallback = new NetdCallback();
+ try {
+ mNetd.registerUnsolicitedEventListener(mNetdCallback);
+ } catch (RemoteException e) {
+ mLog.e("Unable to register netd UnsolicitedEventListener");
+ }
startStateMachineUpdaters(mHandler);
startTrackDefaultNetwork();
@@ -1943,7 +1944,8 @@
parcel.tetheringSupported = mDeps.isTetheringSupported();
parcel.upstreamNetwork = mTetherUpstream;
parcel.config = mConfig.toStableParcelable();
- parcel.states = mTetherStatesParcel;
+ parcel.states =
+ mTetherStatesParcel != null ? mTetherStatesParcel : emptyTetherStatesParcel();
try {
callback.onCallbackStarted(parcel);
} catch (RemoteException e) {
@@ -1952,6 +1954,17 @@
});
}
+ private TetherStatesParcel emptyTetherStatesParcel() {
+ final TetherStatesParcel parcel = new TetherStatesParcel();
+ parcel.availableList = new String[0];
+ parcel.tetheredList = new String[0];
+ parcel.localOnlyList = new String[0];
+ parcel.erroredIfaceList = new String[0];
+ parcel.lastErrorList = new int[0];
+
+ return parcel;
+ }
+
/** Unregister tethering event callback */
void unregisterTetheringEventCallback(ITetheringEventCallback callback) {
mHandler.post(() -> {
diff --git a/Tethering/tests/unit/Android.bp b/Tethering/tests/unit/Android.bp
index 13174c5..c6905ec 100644
--- a/Tethering/tests/unit/Android.bp
+++ b/Tethering/tests/unit/Android.bp
@@ -34,7 +34,15 @@
"TetheringApiCurrentLib",
"testables",
],
+ // TODO(b/147200698) change sdk_version to module-current and
+ // remove framework-minus-apex, ext, and framework-res
+ sdk_version: "core_platform",
libs: [
+ "framework-minus-apex",
+ "ext",
+ "framework-res",
+ "framework-wifi-stubs",
+ "framework-telephony-stubs",
"android.test.runner",
"android.test.base",
"android.test.mock",
diff --git a/Tethering/tests/unit/src/android/net/TetheredClientTest.kt b/Tethering/tests/unit/src/android/net/TetheredClientTest.kt
index 83c19ec..d85389a 100644
--- a/Tethering/tests/unit/src/android/net/TetheredClientTest.kt
+++ b/Tethering/tests/unit/src/android/net/TetheredClientTest.kt
@@ -75,7 +75,7 @@
assertNotEquals(makeTestClient(), TetheredClient(
TEST_MACADDR,
listOf(TEST_ADDRINFO1, TEST_ADDRINFO2),
- TETHERING_BLUETOOTH))
+ TETHERING_USB))
}
@Test
diff --git a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 4710287..6d49e20 100644
--- a/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -127,6 +127,7 @@
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.networkstack.tethering.R;
+import com.android.testutils.MiscAssertsKt;
import org.junit.After;
import org.junit.Before;
@@ -1220,6 +1221,16 @@
}
}
+ private void assertTetherStatesNotNullButEmpty(final TetherStatesParcel parcel) {
+ assertFalse(parcel == null);
+ assertEquals(0, parcel.availableList.length);
+ assertEquals(0, parcel.tetheredList.length);
+ assertEquals(0, parcel.localOnlyList.length);
+ assertEquals(0, parcel.erroredIfaceList.length);
+ assertEquals(0, parcel.lastErrorList.length);
+ MiscAssertsKt.assertFieldCountEquals(5, TetherStatesParcel.class);
+ }
+
@Test
public void testRegisterTetheringEventCallback() throws Exception {
TestTetheringEventCallback callback = new TestTetheringEventCallback();
@@ -1232,7 +1243,7 @@
callback.expectConfigurationChanged(
mTethering.getTetheringConfiguration().toStableParcelable());
TetherStatesParcel tetherState = callback.pollTetherStatesChanged();
- assertEquals(tetherState, null);
+ assertTetherStatesNotNullButEmpty(tetherState);
// 2. Enable wifi tethering.
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);