Merge "Manual start tethering if it doesn't restart automatically"
diff --git a/bpf_progs/bpf_tethering.h b/bpf_progs/bpf_tethering.h
index f9ef6ef..9dae6c9 100644
--- a/bpf_progs/bpf_tethering.h
+++ b/bpf_progs/bpf_tethering.h
@@ -26,31 +26,33 @@
// - The BPF programs in Tethering/bpf_progs/
// - JNI code that depends on the bpf_connectivity_headers library.
-#define BPF_TETHER_ERRORS \
- ERR(INVALID_IP_VERSION) \
- ERR(LOW_TTL) \
- ERR(INVALID_TCP_HEADER) \
- ERR(TCP_CONTROL_PACKET) \
- ERR(NON_GLOBAL_SRC) \
- ERR(NON_GLOBAL_DST) \
- ERR(LOCAL_SRC_DST) \
- ERR(NO_STATS_ENTRY) \
- ERR(NO_LIMIT_ENTRY) \
- ERR(BELOW_IPV4_MTU) \
- ERR(BELOW_IPV6_MTU) \
- ERR(LIMIT_REACHED) \
- ERR(CHANGE_HEAD_FAILED) \
- ERR(TOO_SHORT) \
- ERR(HAS_IP_OPTIONS) \
- ERR(IS_IP_FRAG) \
- ERR(CHECKSUM) \
- ERR(NON_TCP_UDP) \
- ERR(NON_TCP) \
- ERR(SHORT_L4_HEADER) \
- ERR(SHORT_TCP_HEADER) \
- ERR(SHORT_UDP_HEADER) \
- ERR(UDP_CSUM_ZERO) \
- ERR(TRUNCATED_IPV4) \
+#define BPF_TETHER_ERRORS \
+ ERR(INVALID_IPV4_VERSION) \
+ ERR(INVALID_IPV6_VERSION) \
+ ERR(LOW_TTL) \
+ ERR(INVALID_TCP_HEADER) \
+ ERR(TCPV4_CONTROL_PACKET) \
+ ERR(TCPV6_CONTROL_PACKET) \
+ ERR(NON_GLOBAL_SRC) \
+ ERR(NON_GLOBAL_DST) \
+ ERR(LOCAL_SRC_DST) \
+ ERR(NO_STATS_ENTRY) \
+ ERR(NO_LIMIT_ENTRY) \
+ ERR(BELOW_IPV4_MTU) \
+ ERR(BELOW_IPV6_MTU) \
+ ERR(LIMIT_REACHED) \
+ ERR(CHANGE_HEAD_FAILED) \
+ ERR(TOO_SHORT) \
+ ERR(HAS_IP_OPTIONS) \
+ ERR(IS_IP_FRAG) \
+ ERR(CHECKSUM) \
+ ERR(NON_TCP_UDP) \
+ ERR(NON_TCP) \
+ ERR(SHORT_L4_HEADER) \
+ ERR(SHORT_TCP_HEADER) \
+ ERR(SHORT_UDP_HEADER) \
+ ERR(UDP_CSUM_ZERO) \
+ ERR(TRUNCATED_IPV4) \
ERR(_MAX)
#define ERR(x) BPF_TETHER_ERR_ ##x,
diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c
index 898f2e2..bb9fc34 100644
--- a/bpf_progs/offload.c
+++ b/bpf_progs/offload.c
@@ -155,7 +155,7 @@
if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_PIPE;
// IP version must be 6
- if (ip6->version != 6) TC_PUNT(INVALID_IP_VERSION);
+ if (ip6->version != 6) TC_PUNT(INVALID_IPV6_VERSION);
// Cannot decrement during forward if already zero or would be zero,
// Let the kernel's stack handle these cases and generate appropriate ICMP errors.
@@ -171,7 +171,7 @@
TC_PUNT(INVALID_TCP_HEADER);
// Do not offload TCP packets with any one of the SYN/FIN/RST flags
- if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCP_CONTROL_PACKET);
+ if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCPV6_CONTROL_PACKET);
}
// Protect against forwarding packets sourced from ::1 or fe80::/64 or other weirdness.
@@ -370,7 +370,7 @@
// If hardware offload is running and programming flows based on conntrack entries, try not
// to interfere with it, so do not offload TCP packets with any one of the SYN/FIN/RST flags
- if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCP_CONTROL_PACKET);
+ if (tcph->syn || tcph->fin || tcph->rst) TC_PUNT(TCPV4_CONTROL_PACKET);
} else { // UDP
// Make sure we can get at the udp header
if (data + l2_header_size + sizeof(*ip) + sizeof(*udph) > data_end)
@@ -576,7 +576,7 @@
if (is_ethernet && (eth->h_proto != htons(ETH_P_IP))) return TC_ACT_PIPE;
// IP version must be 4
- if (ip->version != 4) TC_PUNT(INVALID_IP_VERSION);
+ if (ip->version != 4) TC_PUNT(INVALID_IPV4_VERSION);
// We cannot handle IP options, just standard 20 byte == 5 dword minimal IPv4 header
if (ip->ihl != 5) TC_PUNT(HAS_IP_OPTIONS);
diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java
index 4f9d845..b7a6076 100644
--- a/framework/src/android/net/NetworkRequest.java
+++ b/framework/src/android/net/NetworkRequest.java
@@ -423,7 +423,6 @@
*
* @deprecated Use {@link #setNetworkSpecifier(NetworkSpecifier)} instead.
*/
- @SuppressLint("NewApi") // TODO: b/193460475 remove once fixed
@Deprecated
public Builder setNetworkSpecifier(String networkSpecifier) {
try {
@@ -440,15 +439,6 @@
} else if (mNetworkCapabilities.hasTransport(TRANSPORT_TEST)) {
return setNetworkSpecifier(new TestNetworkSpecifier(networkSpecifier));
} else {
- // TODO: b/193460475 remove comment once fixed
- // @SuppressLint("NewApi") is due to EthernetNetworkSpecifier being changed
- // from @SystemApi to public. EthernetNetworkSpecifier was introduced in Android
- // 12 as @SystemApi(client = MODULE_LIBRARIES) and made public in Android 13.
- // b/193460475 means in the above situation the tools will think
- // EthernetNetworkSpecifier didn't exist in Android 12, causing the NewApi lint
- // to fail. In this case, this is actually safe because this code was
- // modularized in Android 12, so it can't run on SDKs before Android 12 and is
- // therefore guaranteed to always have this class available to it.
return setNetworkSpecifier(new EthernetNetworkSpecifier(networkSpecifier));
}
}
diff --git a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
index 8b6526f..a3299a7 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
@@ -93,118 +93,6 @@
return env->NewLongArray(size);
}
-static int legacyReadNetworkStatsDetail(std::vector<stats_line>* lines,
- const std::vector<std::string>& limitIfaces,
- int limitTag, int limitUid, const char* path) {
- FILE* fp = fopen(path, "re");
- if (fp == NULL) {
- return -1;
- }
-
- int lastIdx = 1;
- int idx;
- char buffer[384];
- while (fgets(buffer, sizeof(buffer), fp) != NULL) {
- stats_line s;
- int64_t rawTag;
- char* pos = buffer;
- char* endPos;
- // First field is the index.
- idx = (int)strtol(pos, &endPos, 10);
- //ALOGI("Index #%d: %s", idx, buffer);
- if (pos == endPos) {
- // Skip lines that don't start with in index. In particular,
- // this will skip the initial header line.
- continue;
- }
- if (idx != lastIdx + 1) {
- ALOGE("inconsistent idx=%d after lastIdx=%d: %s", idx, lastIdx, buffer);
- fclose(fp);
- return -1;
- }
- lastIdx = idx;
- pos = endPos;
- // Skip whitespace.
- while (*pos == ' ') {
- pos++;
- }
- // Next field is iface.
- int ifaceIdx = 0;
- while (*pos != ' ' && *pos != 0 && ifaceIdx < (int)(sizeof(s.iface)-1)) {
- s.iface[ifaceIdx] = *pos;
- ifaceIdx++;
- pos++;
- }
- if (*pos != ' ') {
- ALOGE("bad iface: %s", buffer);
- fclose(fp);
- return -1;
- }
- s.iface[ifaceIdx] = 0;
- if (limitIfaces.size() > 0) {
- // Is this an iface the caller is interested in?
- int i = 0;
- while (i < (int)limitIfaces.size()) {
- if (limitIfaces[i] == s.iface) {
- break;
- }
- i++;
- }
- if (i >= (int)limitIfaces.size()) {
- // Nothing matched; skip this line.
- //ALOGI("skipping due to iface: %s", buffer);
- continue;
- }
- }
-
- // Ignore whitespace
- while (*pos == ' ') pos++;
-
- // Find end of tag field
- endPos = pos;
- while (*endPos != ' ') endPos++;
-
- // Three digit field is always 0x0, otherwise parse
- if (endPos - pos == 3) {
- rawTag = 0;
- } else {
- if (sscanf(pos, "%" PRIx64, &rawTag) != 1) {
- ALOGE("bad tag: %s", pos);
- fclose(fp);
- return -1;
- }
- }
- s.tag = rawTag >> 32;
- if (limitTag != -1 && s.tag != static_cast<uint32_t>(limitTag)) {
- //ALOGI("skipping due to tag: %s", buffer);
- continue;
- }
- pos = endPos;
-
- // Ignore whitespace
- while (*pos == ' ') pos++;
-
- // Parse remaining fields.
- if (sscanf(pos, "%u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64,
- &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
- &s.txBytes, &s.txPackets) == 6) {
- if (limitUid != -1 && static_cast<uint32_t>(limitUid) != s.uid) {
- //ALOGI("skipping due to uid: %s", buffer);
- continue;
- }
- lines->push_back(s);
- } else {
- //ALOGI("skipping due to bad remaining fields: %s", pos);
- }
- }
-
- if (fclose(fp) != 0) {
- ALOGE("Failed to close netstats file");
- return -1;
- }
- return 0;
-}
-
static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats,
std::vector<stats_line>& lines) {
int size = lines.size();
@@ -282,9 +170,8 @@
return 0;
}
-static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path,
- jint limitUid, jobjectArray limitIfacesObj, jint limitTag,
- jboolean useBpfStats) {
+static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jint limitUid,
+ jobjectArray limitIfacesObj, jint limitTag) {
std::vector<std::string> limitIfaces;
if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
@@ -299,20 +186,8 @@
}
std::vector<stats_line> lines;
-
- if (useBpfStats) {
- if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
- return -1;
- } else {
- ScopedUtfChars path8(env, path);
- if (path8.c_str() == NULL) {
- ALOGE("the qtaguid legacy path is invalid: %s", path8.c_str());
- return -1;
- }
- if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag,
- limitUid, path8.c_str()) < 0)
- return -1;
- }
+ if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
+ return -1;
return statsLinesToNetworkStats(env, clazz, stats, lines);
}
@@ -328,7 +203,7 @@
static const JNINativeMethod gMethods[] = {
{ "nativeReadNetworkStatsDetail",
- "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I",
+ "(Landroid/net/NetworkStats;I[Ljava/lang/String;I)I",
(void*) readNetworkStatsDetail },
{ "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I",
(void*) readNetworkStatsDev },
diff --git a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
index e4445d0..17abbab 100644
--- a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
+++ b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
@@ -18,7 +18,6 @@
import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
-import android.annotation.Nullable;
import android.content.ApexEnvironment;
import android.net.IpConfiguration;
import android.os.Environment;
@@ -47,7 +46,6 @@
private IpConfigStore mStore = new IpConfigStore();
private final ArrayMap<String, IpConfiguration> mIpConfigurations;
- private IpConfiguration mIpConfigurationForDefaultInterface;
private final Object mSync = new Object();
public EthernetConfigStore() {
@@ -144,9 +142,4 @@
return new ArrayMap<>(mIpConfigurations);
}
}
-
- @Nullable
- public IpConfiguration getIpConfigurationForDefaultInterface() {
- return null;
- }
}
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java
index be9beed..7f353a3 100644
--- a/service-t/src/com/android/server/ethernet/EthernetTracker.java
+++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -43,15 +43,21 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.PermissionUtils;
+import com.android.net.module.util.SharedLog;
+import com.android.net.module.util.ip.NetlinkMonitor;
+import com.android.net.module.util.netlink.NetlinkConstants;
+import com.android.net.module.util.netlink.NetlinkMessage;
+import com.android.net.module.util.netlink.RtNetlinkLinkMessage;
+import com.android.net.module.util.netlink.StructIfinfoMsg;
import java.io.FileDescriptor;
import java.net.InetAddress;
@@ -86,6 +92,9 @@
private static final String TEST_IFACE_REGEXP = TEST_TAP_PREFIX + "\\d+";
+ // TODO: consider using SharedLog consistently across ethernet service.
+ private static final SharedLog sLog = new SharedLog(TAG);
+
/**
* Interface names we track. This is a product-dependent regular expression.
* Use isValidEthernetInterface to check if a interface name is a valid ethernet interface (this
@@ -110,6 +119,7 @@
private final Handler mHandler;
private final EthernetNetworkFactory mFactory;
private final EthernetConfigStore mConfigStore;
+ private final NetlinkMonitor mNetlinkMonitor;
private final Dependencies mDeps;
private final RemoteCallbackList<IEthernetServiceListener> mListeners =
@@ -117,12 +127,13 @@
private final TetheredInterfaceRequestList mTetheredInterfaceRequests =
new TetheredInterfaceRequestList();
- // Used only on the handler thread
- private String mDefaultInterface;
- private int mDefaultInterfaceMode = INTERFACE_MODE_CLIENT;
+ // The first interface discovered is set as the mTetheringInterface. It is the interface that is
+ // returned when a tethered interface is requested; until then, it remains in client mode. Its
+ // current mode is reflected in mTetheringInterfaceMode.
+ private String mTetheringInterface;
+ private int mTetheringInterfaceMode = INTERFACE_MODE_CLIENT;
// Tracks whether clients were notified that the tethered interface is available
private boolean mTetheredInterfaceWasAvailable = false;
- private volatile IpConfiguration mIpConfigForDefaultInterface;
private int mEthernetState = ETHERNET_STATE_ENABLED;
@@ -130,7 +141,7 @@
RemoteCallbackList<ITetheredInterfaceCallback> {
@Override
public void onCallbackDied(ITetheredInterfaceCallback cb, Object cookie) {
- mHandler.post(EthernetTracker.this::maybeUntetherDefaultInterface);
+ mHandler.post(EthernetTracker.this::maybeUntetherInterface);
}
}
@@ -148,6 +159,69 @@
}
}
+ private class EthernetNetlinkMonitor extends NetlinkMonitor {
+ EthernetNetlinkMonitor(Handler handler) {
+ super(handler, sLog, EthernetNetlinkMonitor.class.getSimpleName(),
+ OsConstants.NETLINK_ROUTE, NetlinkConstants.RTMGRP_LINK);
+ }
+
+ private void onNewLink(String ifname, boolean linkUp) {
+ if (!mFactory.hasInterface(ifname) && !ifname.equals(mTetheringInterface)) {
+ Log.i(TAG, "onInterfaceAdded, iface: " + ifname);
+ maybeTrackInterface(ifname);
+ }
+ Log.i(TAG, "interfaceLinkStateChanged, iface: " + ifname + ", up: " + linkUp);
+ updateInterfaceState(ifname, linkUp);
+ }
+
+ private void onDelLink(String ifname) {
+ Log.i(TAG, "onInterfaceRemoved, iface: " + ifname);
+ stopTrackingInterface(ifname);
+ }
+
+ private void processRtNetlinkLinkMessage(RtNetlinkLinkMessage msg) {
+ final StructIfinfoMsg ifinfomsg = msg.getIfinfoHeader();
+ // check if the message is valid
+ if (ifinfomsg.family != OsConstants.AF_UNSPEC) return;
+
+ // ignore messages for the loopback interface
+ if ((ifinfomsg.flags & OsConstants.IFF_LOOPBACK) != 0) return;
+
+ // check if the received message applies to an ethernet interface.
+ final String ifname = msg.getInterfaceName();
+ if (!isValidEthernetInterface(ifname)) return;
+
+ switch (msg.getHeader().nlmsg_type) {
+ case NetlinkConstants.RTM_NEWLINK:
+ final boolean linkUp = (ifinfomsg.flags & NetlinkConstants.IFF_LOWER_UP) != 0;
+ onNewLink(ifname, linkUp);
+ break;
+
+ case NetlinkConstants.RTM_DELLINK:
+ onDelLink(ifname);
+ break;
+
+ default:
+ Log.e(TAG, "Unknown rtnetlink link msg type: " + msg);
+ break;
+ }
+ }
+
+ // Note: processNetlinkMessage is called on the handler thread.
+ @Override
+ protected void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) {
+ // ignore all updates when ethernet is disabled.
+ if (mEthernetState == ETHERNET_STATE_DISABLED) return;
+
+ if (nlMsg instanceof RtNetlinkLinkMessage) {
+ processRtNetlinkLinkMessage((RtNetlinkLinkMessage) nlMsg);
+ } else {
+ Log.e(TAG, "Unknown netlink message: " + nlMsg);
+ }
+ }
+ }
+
+
EthernetTracker(@NonNull final Context context, @NonNull final Handler handler,
@NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd) {
this(context, handler, factory, netd, new Dependencies());
@@ -173,27 +247,22 @@
}
mConfigStore = new EthernetConfigStore();
+ mNetlinkMonitor = new EthernetNetlinkMonitor(mHandler);
}
void start() {
mFactory.register();
mConfigStore.read();
- // Default interface is just the first one we want to track.
- mIpConfigForDefaultInterface = mConfigStore.getIpConfigurationForDefaultInterface();
final ArrayMap<String, IpConfiguration> configs = mConfigStore.getIpConfigurations();
for (int i = 0; i < configs.size(); i++) {
mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i));
}
- try {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- mNetd.registerUnsolicitedEventListener(new InterfaceObserver());
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Could not register InterfaceObserver " + e);
- }
-
- mHandler.post(this::trackAvailableInterfaces);
+ mHandler.post(() -> {
+ mNetlinkMonitor.start();
+ trackAvailableInterfaces();
+ });
}
void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
@@ -401,21 +470,21 @@
// Remote process has already died
return;
}
- if (mDefaultInterfaceMode == INTERFACE_MODE_SERVER) {
+ if (mTetheringInterfaceMode == INTERFACE_MODE_SERVER) {
if (mTetheredInterfaceWasAvailable) {
- notifyTetheredInterfaceAvailable(callback, mDefaultInterface);
+ notifyTetheredInterfaceAvailable(callback, mTetheringInterface);
}
return;
}
- setDefaultInterfaceMode(INTERFACE_MODE_SERVER);
+ setTetheringInterfaceMode(INTERFACE_MODE_SERVER);
});
}
public void releaseTetheredInterface(ITetheredInterfaceCallback callback) {
mHandler.post(() -> {
mTetheredInterfaceRequests.unregister(callback);
- maybeUntetherDefaultInterface();
+ maybeUntetherInterface();
});
}
@@ -435,21 +504,21 @@
}
}
- private void maybeUntetherDefaultInterface() {
+ private void maybeUntetherInterface() {
if (mTetheredInterfaceRequests.getRegisteredCallbackCount() > 0) return;
- if (mDefaultInterfaceMode == INTERFACE_MODE_CLIENT) return;
- setDefaultInterfaceMode(INTERFACE_MODE_CLIENT);
+ if (mTetheringInterfaceMode == INTERFACE_MODE_CLIENT) return;
+ setTetheringInterfaceMode(INTERFACE_MODE_CLIENT);
}
- private void setDefaultInterfaceMode(int mode) {
- Log.d(TAG, "Setting default interface mode to " + mode);
- mDefaultInterfaceMode = mode;
- if (mDefaultInterface != null) {
- removeInterface(mDefaultInterface);
- addInterface(mDefaultInterface);
+ private void setTetheringInterfaceMode(int mode) {
+ Log.d(TAG, "Setting tethering interface mode to " + mode);
+ mTetheringInterfaceMode = mode;
+ if (mTetheringInterface != null) {
+ removeInterface(mTetheringInterface);
+ addInterface(mTetheringInterface);
// when this broadcast is sent, any calls to notifyTetheredInterfaceAvailable or
// notifyTetheredInterfaceUnavailable have already happened
- broadcastInterfaceStateChange(mDefaultInterface);
+ broadcastInterfaceStateChange(mTetheringInterface);
}
}
@@ -478,8 +547,8 @@
}
private int getInterfaceMode(final String iface) {
- if (iface.equals(mDefaultInterface)) {
- return mDefaultInterfaceMode;
+ if (iface.equals(mTetheringInterface)) {
+ return mTetheringInterfaceMode;
}
return INTERFACE_MODE_CLIENT;
}
@@ -491,8 +560,8 @@
private void stopTrackingInterface(String iface) {
removeInterface(iface);
- if (iface.equals(mDefaultInterface)) {
- mDefaultInterface = null;
+ if (iface.equals(mTetheringInterface)) {
+ mTetheringInterface = null;
}
broadcastInterfaceStateChange(iface);
}
@@ -560,7 +629,9 @@
}
private void maybeUpdateServerModeInterfaceState(String iface, boolean available) {
- if (available == mTetheredInterfaceWasAvailable || !iface.equals(mDefaultInterface)) return;
+ if (available == mTetheredInterfaceWasAvailable || !iface.equals(mTetheringInterface)) {
+ return;
+ }
Log.d(TAG, (available ? "Tracking" : "No longer tracking")
+ " interface in server mode: " + iface);
@@ -585,20 +656,15 @@
// If we don't already track this interface, and if this interface matches
// our regex, start tracking it.
- if (mFactory.hasInterface(iface) || iface.equals(mDefaultInterface)) {
+ if (mFactory.hasInterface(iface) || iface.equals(mTetheringInterface)) {
if (DBG) Log.w(TAG, "Ignoring already-tracked interface " + iface);
return;
}
if (DBG) Log.i(TAG, "maybeTrackInterface: " + iface);
- // Do not make an interface default if it has configured NetworkCapabilities.
- if (mDefaultInterface == null && !mNetworkCapabilities.containsKey(iface)) {
- mDefaultInterface = iface;
- }
-
- if (mIpConfigForDefaultInterface != null) {
- updateIpConfiguration(iface, mIpConfigForDefaultInterface);
- mIpConfigForDefaultInterface = null;
+ // Do not use an interface for tethering if it has configured NetworkCapabilities.
+ if (mTetheringInterface == null && !mNetworkCapabilities.containsKey(iface)) {
+ mTetheringInterface = iface;
}
addInterface(iface);
@@ -617,43 +683,6 @@
}
}
- @VisibleForTesting
- class InterfaceObserver extends BaseNetdUnsolicitedEventListener {
-
- @Override
- public void onInterfaceLinkStateChanged(String iface, boolean up) {
- if (DBG) {
- Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up);
- }
- mHandler.post(() -> {
- if (mEthernetState == ETHERNET_STATE_DISABLED) return;
- updateInterfaceState(iface, up);
- });
- }
-
- @Override
- public void onInterfaceAdded(String iface) {
- if (DBG) {
- Log.i(TAG, "onInterfaceAdded, iface: " + iface);
- }
- mHandler.post(() -> {
- if (mEthernetState == ETHERNET_STATE_DISABLED) return;
- maybeTrackInterface(iface);
- });
- }
-
- @Override
- public void onInterfaceRemoved(String iface) {
- if (DBG) {
- Log.i(TAG, "onInterfaceRemoved, iface: " + iface);
- }
- mHandler.post(() -> {
- if (mEthernetState == ETHERNET_STATE_DISABLED) return;
- stopTrackingInterface(iface);
- });
- }
- }
-
private static class ListenerInfo {
boolean canUseRestrictedNetworks = false;
@@ -928,8 +957,8 @@
pw.println("Ethernet State: "
+ (mEthernetState == ETHERNET_STATE_ENABLED ? "enabled" : "disabled"));
pw.println("Ethernet interface name filter: " + mIfaceMatch);
- pw.println("Default interface: " + mDefaultInterface);
- pw.println("Default interface mode: " + mDefaultInterfaceMode);
+ pw.println("Interface used for tethering: " + mTetheringInterface);
+ pw.println("Tethering interface mode: " + mTetheringInterfaceMode);
pw.println("Tethered interface requests: "
+ mTetheredInterfaceRequests.getRegisteredCallbackCount());
pw.println("Listeners: " + mListeners.getRegisteredCallbackCount());
diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java
index 4a6741c..c9d1718 100644
--- a/service-t/src/com/android/server/net/NetworkStatsFactory.java
+++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java
@@ -91,8 +91,7 @@
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
// TODO: remove both path and useBpfStats arguments.
// The path is never used if useBpfStats is true.
- final int ret = nativeReadNetworkStatsDetail(stats, null /* path */,
- limitUid, limitIfaces, limitTag, true /* useBpfStats */);
+ final int ret = nativeReadNetworkStatsDetail(stats, limitUid, limitIfaces, limitTag);
if (ret != 0) {
throw new IOException("Failed to parse network stats");
}
@@ -334,8 +333,8 @@
* are expected to monotonically increase since device boot.
*/
@VisibleForTesting
- public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path,
- int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats);
+ public static native int nativeReadNetworkStatsDetail(NetworkStats stats, int limitUid,
+ String[] limitIfaces, int limitTag);
@VisibleForTesting
public static native int nativeReadNetworkStatsDev(NetworkStats stats);
diff --git a/service/Android.bp b/service/Android.bp
index 7dcc888..b68d389 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -143,8 +143,6 @@
"src/**/*.java",
":framework-connectivity-shared-srcs",
":services-connectivity-shared-srcs",
- // TODO: move to net-utils-device-common
- ":connectivity-module-utils-srcs",
],
libs: [
"framework-annotations-lib",
@@ -164,6 +162,7 @@
"modules-utils-shell-command-handler",
"net-utils-device-common",
"net-utils-device-common-bpf",
+ "net-utils-device-common-ip",
"net-utils-device-common-netlink",
"net-utils-services-common",
"netd-client",
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index 303112f..a26d1e6 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -572,17 +572,6 @@
}
}
-std::string getProgramStatus(const char *path) {
- int ret = access(path, R_OK);
- if (ret == 0) {
- return StringPrintf("OK");
- }
- if (ret != 0 && errno == ENOENT) {
- return StringPrintf("program is missing at: %s", path);
- }
- return StringPrintf("check Program %s error: %s", path, strerror(errno));
-}
-
std::string getMapStatus(const base::unique_fd& map_fd, const char* path) {
if (map_fd.get() < 0) {
return StringPrintf("map fd lost");
@@ -614,6 +603,10 @@
dw.blankline();
dw.println("mCookieTagMap status: %s",
getMapStatus(mCookieTagMap.getMap(), COOKIE_TAG_MAP_PATH).c_str());
+ dw.println("mUidCounterSetMap status: %s",
+ getMapStatus(mUidCounterSetMap.getMap(), UID_COUNTERSET_MAP_PATH).c_str());
+ dw.println("mAppUidStatsMap status: %s",
+ getMapStatus(mAppUidStatsMap.getMap(), APP_UID_STATS_MAP_PATH).c_str());
dw.println("mStatsMapA status: %s",
getMapStatus(mStatsMapA.getMap(), STATS_MAP_A_PATH).c_str());
dw.println("mStatsMapB status: %s",
@@ -627,19 +620,6 @@
dw.println("mUidOwnerMap status: %s",
getMapStatus(mUidOwnerMap.getMap(), UID_OWNER_MAP_PATH).c_str());
- dw.blankline();
- dw.println("Cgroup ingress program status: %s",
- getProgramStatus(BPF_INGRESS_PROG_PATH).c_str());
- dw.println("Cgroup egress program status: %s", getProgramStatus(BPF_EGRESS_PROG_PATH).c_str());
- dw.println("xt_bpf ingress program status: %s",
- getProgramStatus(XT_BPF_INGRESS_PROG_PATH).c_str());
- dw.println("xt_bpf egress program status: %s",
- getProgramStatus(XT_BPF_EGRESS_PROG_PATH).c_str());
- dw.println("xt_bpf bandwidth allowlist program status: %s",
- getProgramStatus(XT_BPF_ALLOWLIST_PROG_PATH).c_str());
- dw.println("xt_bpf bandwidth denylist program status: %s",
- getProgramStatus(XT_BPF_DENYLIST_PROG_PATH).c_str());
-
if (!verbose) {
return;
}
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 0ca0d83..1caca01 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -89,7 +89,6 @@
import static android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY;
-import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
import static android.os.Process.INVALID_UID;
import static android.os.Process.VPN_UID;
import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
@@ -98,6 +97,7 @@
import static android.system.OsConstants.IPPROTO_UDP;
import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
+import static com.android.net.module.util.NetworkMonitorUtils.isPrivateDnsValidationRequired;
import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf;
import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission;
import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr;
@@ -1220,16 +1220,7 @@
public void incrementCountOrThrow(final int uid) {
synchronized (mUidToNetworkRequestCount) {
final int newRequestCount = mUidToNetworkRequestCount.get(uid, 0) + 1;
- if (newRequestCount >= mMaxCountPerUid
- // HACK : the system server is allowed to go over the request count limit
- // when it is creating requests on behalf of another app (but not itself,
- // so it can still detect its own request leaks). This only happens in the
- // per-app API flows in which case the old requests for that particular
- // UID will be removed soon.
- // TODO : with the removal of the legacy transact() method, exempting the
- // system server UID should no longer be necessary. Make sure this is the
- // case and remove this test.
- && (Process.myUid() == uid || Process.myUid() != Binder.getCallingUid())) {
+ if (newRequestCount >= mMaxCountPerUid) {
throw new ServiceSpecificException(
ConnectivityManager.Errors.TOO_MANY_REQUESTS,
"Uid " + uid + " exceeded its allotted requests limit");
@@ -10856,6 +10847,7 @@
removeDefaultNetworkRequestsForPreference(PREFERENCE_ORDER_PROFILE);
addPerAppDefaultNetworkRequests(
createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences));
+
// Finally, rematch.
rematchAllNetworksAndRequests();
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 06f7300..f8e70c4 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -300,7 +300,6 @@
import android.net.networkstack.NetworkStackClientBase;
import android.net.resolv.aidl.Nat64PrefixEventParcel;
import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
-import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
import android.net.wifi.WifiInfo;
@@ -356,6 +355,7 @@
import com.android.net.module.util.ArrayTrackRecord;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.LocationPermissionChecker;
+import com.android.net.module.util.NetworkMonitorUtils;
import com.android.networkstack.apishim.NetworkAgentConfigShimImpl;
import com.android.networkstack.apishim.api29.ConstantsShim;
import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
@@ -2989,8 +2989,7 @@
@Test
public void testRequiresValidation() {
- assertTrue(NetworkMonitorUtils.isValidationRequired(
- NetworkAgentConfigShimImpl.newInstance(null),
+ assertTrue(NetworkMonitorUtils.isValidationRequired(false /* isVpnValidationRequired */,
mCm.getDefaultRequest().networkCapabilities));
}
@@ -7980,7 +7979,8 @@
// VPN networks do not satisfy the default request and are automatically validated
// by NetworkMonitor
assertFalse(NetworkMonitorUtils.isValidationRequired(
- NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig()),
+ NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig())
+ .isVpnValidationRequired(),
mMockVpn.getAgent().getNetworkCapabilities()));
mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
@@ -8131,7 +8131,8 @@
assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
assertFalse(NetworkMonitorUtils.isValidationRequired(
- NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig()),
+ NetworkAgentConfigShimImpl.newInstance(mMockVpn.getNetworkAgentConfig())
+ .isVpnValidationRequired(),
mMockVpn.getAgent().getNetworkCapabilities()));
assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired(
mMockVpn.getAgent().getNetworkCapabilities()));
diff --git a/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java
index 38094ae..0376a2a 100644
--- a/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java
+++ b/tests/unit/java/com/android/server/ethernet/EthernetTrackerTest.java
@@ -30,10 +30,8 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -64,7 +62,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -476,43 +473,4 @@
verify(listener).onInterfaceStateChanged(eq(testIface), eq(EthernetManager.STATE_LINK_UP),
anyInt(), any());
}
-
- @Test
- public void testListenEthernetStateChange_unsolicitedEventListener() throws Exception {
- when(mNetd.interfaceGetList()).thenReturn(new String[] {});
- doReturn(new String[] {}).when(mFactory).getAvailableInterfaces(anyBoolean());
-
- tracker.setIncludeTestInterfaces(true);
- tracker.start();
-
- final ArgumentCaptor<EthernetTracker.InterfaceObserver> captor =
- ArgumentCaptor.forClass(EthernetTracker.InterfaceObserver.class);
- verify(mNetd, timeout(TIMEOUT_MS)).registerUnsolicitedEventListener(captor.capture());
- final EthernetTracker.InterfaceObserver observer = captor.getValue();
-
- tracker.setEthernetEnabled(false);
- waitForIdle();
- reset(mFactory);
- reset(mNetd);
-
- final String testIface = "testtap1";
- observer.onInterfaceAdded(testIface);
- verify(mFactory, never()).addInterface(eq(testIface), anyString(), any(), any());
- observer.onInterfaceRemoved(testIface);
- verify(mFactory, never()).removeInterface(eq(testIface));
-
- final String testHwAddr = "11:22:33:44:55:66";
- final InterfaceConfigurationParcel testIfaceParce =
- createMockedIfaceParcel(testIface, testHwAddr);
- when(mNetd.interfaceGetList()).thenReturn(new String[] {testIface});
- when(mNetd.interfaceGetCfg(eq(testIface))).thenReturn(testIfaceParce);
- doReturn(new String[] {testIface}).when(mFactory).getAvailableInterfaces(anyBoolean());
- tracker.setEthernetEnabled(true);
- waitForIdle();
- reset(mFactory);
-
- final String testIface2 = "testtap2";
- observer.onInterfaceRemoved(testIface2);
- verify(mFactory, timeout(TIMEOUT_MS)).removeInterface(eq(testIface2));
- }
}