Merge "CGROUPV2_CONTROLLER_NAME -> CGROUPV2_HIERARCHY_NAME" into main
diff --git a/Tethering/src/com/android/networkstack/tethering/util/VersionedBroadcastListener.java b/Tethering/src/com/android/networkstack/tethering/util/VersionedBroadcastListener.java
index c9e75c0..5eb1551 100644
--- a/Tethering/src/com/android/networkstack/tethering/util/VersionedBroadcastListener.java
+++ b/Tethering/src/com/android/networkstack/tethering/util/VersionedBroadcastListener.java
@@ -62,8 +62,8 @@
if (DBG) Log.d(mTag, "startListening");
if (mReceiver != null) return;
- mReceiver = new Receiver(mTag, mGenerationNumber, mCallback);
- mContext.registerReceiver(mReceiver, mFilter, null, mHandler);
+ mReceiver = new Receiver(mTag, mGenerationNumber, mCallback, mHandler);
+ mContext.registerReceiver(mReceiver, mFilter);
}
/** Stop listening to intent broadcast. */
@@ -77,30 +77,35 @@
}
private static class Receiver extends BroadcastReceiver {
- public final String tag;
- public final AtomicInteger atomicGenerationNumber;
- public final Consumer<Intent> callback;
+ final String mTag;
+ final AtomicInteger mAtomicGenerationNumber;
+ final Consumer<Intent> mCallback;
// Used to verify this receiver is still current.
- public final int generationNumber;
+ final int mGenerationNumber;
+ private final Handler mHandler;
- Receiver(String tag, AtomicInteger atomicGenerationNumber, Consumer<Intent> callback) {
- this.tag = tag;
- this.atomicGenerationNumber = atomicGenerationNumber;
- this.callback = callback;
- generationNumber = atomicGenerationNumber.incrementAndGet();
+ Receiver(String tag, AtomicInteger atomicGenerationNumber, Consumer<Intent> callback,
+ Handler handler) {
+ mTag = tag;
+ mAtomicGenerationNumber = atomicGenerationNumber;
+ mCallback = callback;
+ mGenerationNumber = atomicGenerationNumber.incrementAndGet();
+ mHandler = handler;
}
@Override
public void onReceive(Context context, Intent intent) {
- final int currentGenerationNumber = atomicGenerationNumber.get();
+ mHandler.post(() -> {
+ final int currentGenerationNumber = mAtomicGenerationNumber.get();
- if (DBG) {
- Log.d(tag, "receiver generationNumber=" + generationNumber
- + ", current generationNumber=" + currentGenerationNumber);
- }
- if (generationNumber != currentGenerationNumber) return;
+ if (DBG) {
+ Log.d(mTag, "receiver generationNumber=" + mGenerationNumber
+ + ", current generationNumber=" + currentGenerationNumber);
+ }
+ if (mGenerationNumber != currentGenerationNumber) return;
- callback.accept(intent);
+ mCallback.accept(intent);
+ });
}
}
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/util/VersionedBroadcastListenerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/util/VersionedBroadcastListenerTest.java
index b7dc66e..ed4f3da 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/util/VersionedBroadcastListenerTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/util/VersionedBroadcastListenerTest.java
@@ -16,6 +16,8 @@
package com.android.networkstack.tethering.util;
+import static com.android.testutils.HandlerUtils.waitForIdle;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.reset;
@@ -23,7 +25,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
-import android.os.Looper;
+import android.os.HandlerThread;
import android.os.UserHandle;
import androidx.test.filters.SmallTest;
@@ -33,7 +35,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -44,9 +45,11 @@
public class VersionedBroadcastListenerTest {
private static final String TAG = VersionedBroadcastListenerTest.class.getSimpleName();
private static final String ACTION_TEST = "action.test.happy.broadcasts";
+ private static final long TEST_TIMEOUT_MS = 10_000L;
@Mock private Context mContext;
private BroadcastInterceptingContext mServiceContext;
+ private HandlerThread mHandlerThread;
private Handler mHandler;
private VersionedBroadcastListener mListener;
private int mCallbackCount;
@@ -61,18 +64,13 @@
}
}
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
- }
-
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
reset(mContext);
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
mServiceContext = new MockContext(mContext);
- mHandler = new Handler(Looper.myLooper());
mCallbackCount = 0;
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_TEST);
@@ -85,11 +83,15 @@
mListener.stopListening();
mListener = null;
}
+ mHandlerThread.quitSafely();
+ mHandlerThread.join(TEST_TIMEOUT_MS);
}
private void sendBroadcast() {
final Intent intent = new Intent(ACTION_TEST);
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ // Sending the broadcast is synchronous, but the receiver just posts on the handler
+ waitForIdle(mHandler, TEST_TIMEOUT_MS);
}
@Test
diff --git a/common/FlaggedApi.bp b/common/FlaggedApi.bp
index 21be1d3..fef9ac3 100644
--- a/common/FlaggedApi.bp
+++ b/common/FlaggedApi.bp
@@ -22,6 +22,16 @@
visibility: ["//packages/modules/Connectivity:__subpackages__"],
}
+java_aconfig_library {
+ name: "com.android.net.flags-aconfig-java",
+ aconfig_declarations: "com.android.net.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ min_sdk_version: "30",
+ apex_available: [
+ "com.android.tethering",
+ ],
+}
+
aconfig_declarations {
name: "com.android.net.thread.flags-aconfig",
package: "com.android.net.thread.flags",
@@ -37,3 +47,20 @@
srcs: ["nearby_flags.aconfig"],
visibility: ["//packages/modules/Connectivity:__subpackages__"],
}
+
+aconfig_declarations {
+ name: "com.android.networksecurity.flags-aconfig",
+ package: "com.android.net.ct.flags",
+ container: "com.android.tethering",
+ srcs: ["networksecurity_flags.aconfig"],
+ visibility: ["//packages/modules/Connectivity:__subpackages__"],
+}
+
+java_aconfig_library {
+ name: "networksecurity_flags_java_lib",
+ aconfig_declarations: "com.android.networksecurity.flags-aconfig",
+ min_sdk_version: "30",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ apex_available: ["com.android.tethering"],
+ visibility: ["//packages/modules/Connectivity:__subpackages__"],
+}
diff --git a/common/flags.aconfig b/common/flags.aconfig
index b320b61..1b0da4e 100644
--- a/common/flags.aconfig
+++ b/common/flags.aconfig
@@ -123,3 +123,11 @@
description: "Flag for introducing TETHERING_VIRTUAL type"
bug: "340376953"
}
+
+flag {
+ name: "netstats_add_entries"
+ is_exported: true
+ namespace: "android_core_networking"
+ description: "Flag for NetworkStats#addEntries API"
+ bug: "335680025"
+}
diff --git a/common/networksecurity_flags.aconfig b/common/networksecurity_flags.aconfig
new file mode 100644
index 0000000..ef8ffcd
--- /dev/null
+++ b/common/networksecurity_flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.net.ct.flags"
+container: "com.android.tethering"
+flag {
+ name: "certificate_transparency_service"
+ is_exported: true
+ namespace: "network_security"
+ description: "Enable service for certificate transparency log list data"
+ bug: "319829948"
+}
diff --git a/framework-t/Android.bp b/framework-t/Android.bp
index f076f5b..ac78d09 100644
--- a/framework-t/Android.bp
+++ b/framework-t/Android.bp
@@ -137,6 +137,10 @@
// framework-connectivity-pre-jarjar match at runtime.
jarjar_rules: ":framework-connectivity-jarjar-rules",
stub_only_libs: [
+ // static_libs is not used to compile stubs. So libs which have
+ // been included in static_libs might still need to
+ // be in stub_only_libs to be usable when generating the API stubs.
+ "com.android.net.flags-aconfig-java",
// Use prebuilt framework-connectivity stubs to avoid circular dependencies
"sdk_module-lib_current_framework-connectivity",
],
diff --git a/framework-t/api/system-current.txt b/framework-t/api/system-current.txt
index 52de1a3..2354882 100644
--- a/framework-t/api/system-current.txt
+++ b/framework-t/api/system-current.txt
@@ -310,6 +310,7 @@
public final class NetworkStats implements java.lang.Iterable<android.net.NetworkStats.Entry> android.os.Parcelable {
ctor public NetworkStats(long, int);
method @NonNull public android.net.NetworkStats add(@NonNull android.net.NetworkStats);
+ method @FlaggedApi("com.android.net.flags.netstats_add_entries") @NonNull public android.net.NetworkStats addEntries(@NonNull java.util.List<android.net.NetworkStats.Entry>);
method @NonNull public android.net.NetworkStats addEntry(@NonNull android.net.NetworkStats.Entry);
method public android.net.NetworkStats clone();
method public int describeContents();
diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java
index e9a3f58..a2c4fc3 100644
--- a/framework-t/src/android/net/NetworkStats.java
+++ b/framework-t/src/android/net/NetworkStats.java
@@ -18,6 +18,7 @@
import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,6 +34,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.modules.utils.build.SdkLevel;
+import com.android.net.flags.Flags;
import com.android.net.module.util.CollectionUtils;
import libcore.util.EmptyArray;
@@ -845,6 +847,21 @@
}
/**
+ * Adds multiple entries to a copy of this NetworkStats instance.
+ *
+ * @param entries The entries to add.
+ * @return A new NetworkStats instance with the added entries.
+ */
+ @FlaggedApi(Flags.FLAG_NETSTATS_ADD_ENTRIES)
+ public @NonNull NetworkStats addEntries(@NonNull final List<Entry> entries) {
+ final NetworkStats newStats = this.clone();
+ for (final Entry entry : Objects.requireNonNull(entries)) {
+ newStats.combineValues(entry);
+ }
+ return newStats;
+ }
+
+ /**
* Add given values with an existing row, or create a new row if
* {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can
* also be used to subtract values from existing rows.
diff --git a/framework/Android.bp b/framework/Android.bp
index 282ba4b..4c4f792 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -63,6 +63,7 @@
":framework-connectivity-sources",
":net-utils-framework-common-srcs",
":framework-connectivity-api-shared-srcs",
+ ":framework-networksecurity-sources",
],
aidl: {
generate_get_transaction_name: true,
@@ -86,12 +87,14 @@
"framework-wifi.stubs.module_lib",
],
static_libs: [
+ "com.android.net.flags-aconfig-java",
// Not using the latest stable version because all functions in the latest version of
// mdns_aidl_interface are deprecated.
"mdns_aidl_interface-V1-java",
"modules-utils-backgroundthread",
"modules-utils-build",
"modules-utils-preconditions",
+ "networksecurity_flags_java_lib",
"framework-connectivity-javastream-protos",
],
impl_only_static_libs: [
@@ -206,6 +209,7 @@
},
aconfig_declarations: [
"com.android.net.flags-aconfig",
+ "com.android.networksecurity.flags-aconfig",
],
}
@@ -306,6 +310,7 @@
srcs: [
":framework-connectivity-sources",
":framework-connectivity-tiramisu-updatable-sources",
+ ":framework-networksecurity-sources",
":framework-nearby-java-sources",
":framework-thread-sources",
],
diff --git a/netbpfload/NetBpfLoad.cpp b/netbpfload/NetBpfLoad.cpp
index 8b539aa..afb44cc 100644
--- a/netbpfload/NetBpfLoad.cpp
+++ b/netbpfload/NetBpfLoad.cpp
@@ -137,9 +137,6 @@
// Size of the BPF log buffer for verifier logging
#define BPF_LOAD_LOG_SZ 0xfffff
-// Unspecified attach type is 0 which is BPF_CGROUP_INET_INGRESS.
-#define BPF_ATTACH_TYPE_UNSPEC BPF_CGROUP_INET_INGRESS
-
static unsigned int page_size = static_cast<unsigned int>(getpagesize());
constexpr const char* lookupSelinuxContext(const domain d) {
@@ -201,7 +198,7 @@
typedef struct {
const char* name;
enum bpf_prog_type type;
- enum bpf_attach_type expected_attach_type;
+ enum bpf_attach_type attach_type;
} sectionType;
/*
@@ -221,8 +218,8 @@
sectionType sectionNameTypes[] = {
{"bind4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_BIND},
{"bind6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_BIND},
- {"cgroupskb/", BPF_PROG_TYPE_CGROUP_SKB, BPF_ATTACH_TYPE_UNSPEC},
- {"cgroupsock/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_ATTACH_TYPE_UNSPEC},
+ {"cgroupskb/", BPF_PROG_TYPE_CGROUP_SKB},
+ {"cgroupsock/", BPF_PROG_TYPE_CGROUP_SOCK},
{"cgroupsockcreate/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET_SOCK_CREATE},
{"cgroupsockrelease/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET_SOCK_RELEASE},
{"connect4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_CONNECT},
@@ -230,28 +227,24 @@
{"egress/", BPF_PROG_TYPE_CGROUP_SKB, BPF_CGROUP_INET_EGRESS},
{"getsockopt/", BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_CGROUP_GETSOCKOPT},
{"ingress/", BPF_PROG_TYPE_CGROUP_SKB, BPF_CGROUP_INET_INGRESS},
- {"lwt_in/", BPF_PROG_TYPE_LWT_IN, BPF_ATTACH_TYPE_UNSPEC},
- {"lwt_out/", BPF_PROG_TYPE_LWT_OUT, BPF_ATTACH_TYPE_UNSPEC},
- {"lwt_seg6local/", BPF_PROG_TYPE_LWT_SEG6LOCAL, BPF_ATTACH_TYPE_UNSPEC},
- {"lwt_xmit/", BPF_PROG_TYPE_LWT_XMIT, BPF_ATTACH_TYPE_UNSPEC},
{"postbind4/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET4_POST_BIND},
{"postbind6/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET6_POST_BIND},
{"recvmsg4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_RECVMSG},
{"recvmsg6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_RECVMSG},
- {"schedact/", BPF_PROG_TYPE_SCHED_ACT, BPF_ATTACH_TYPE_UNSPEC},
- {"schedcls/", BPF_PROG_TYPE_SCHED_CLS, BPF_ATTACH_TYPE_UNSPEC},
+ {"schedact/", BPF_PROG_TYPE_SCHED_ACT},
+ {"schedcls/", BPF_PROG_TYPE_SCHED_CLS},
{"sendmsg4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_SENDMSG},
{"sendmsg6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_SENDMSG},
{"setsockopt/", BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_CGROUP_SETSOCKOPT},
- {"skfilter/", BPF_PROG_TYPE_SOCKET_FILTER, BPF_ATTACH_TYPE_UNSPEC},
+ {"skfilter/", BPF_PROG_TYPE_SOCKET_FILTER},
{"sockops/", BPF_PROG_TYPE_SOCK_OPS, BPF_CGROUP_SOCK_OPS},
{"sysctl", BPF_PROG_TYPE_CGROUP_SYSCTL, BPF_CGROUP_SYSCTL},
- {"xdp/", BPF_PROG_TYPE_XDP, BPF_ATTACH_TYPE_UNSPEC},
+ {"xdp/", BPF_PROG_TYPE_XDP},
};
typedef struct {
enum bpf_prog_type type;
- enum bpf_attach_type expected_attach_type;
+ enum bpf_attach_type attach_type;
string name;
vector<char> data;
vector<char> rel_data;
@@ -435,12 +428,6 @@
return BPF_PROG_TYPE_UNSPEC;
}
-static enum bpf_attach_type getExpectedAttachType(string& name) {
- for (auto& snt : sectionNameTypes)
- if (StartsWith(name, snt.name)) return snt.expected_attach_type;
- return BPF_ATTACH_TYPE_UNSPEC;
-}
-
/*
static string getSectionName(enum bpf_prog_type type)
{
@@ -556,7 +543,8 @@
if (ptype == BPF_PROG_TYPE_UNSPEC) continue;
// This must be done before '/' is replaced with '_'.
- cs_temp.expected_attach_type = getExpectedAttachType(name);
+ for (auto& snt : sectionNameTypes)
+ if (StartsWith(name, snt.name)) cs_temp.attach_type = snt.attach_type;
string oldName = name;
@@ -1062,7 +1050,7 @@
.log_level = 1,
.log_buf = ptr_to_u64(log_buf.data()),
.log_size = static_cast<__u32>(log_buf.size()),
- .expected_attach_type = cs[i].expected_attach_type,
+ .expected_attach_type = cs[i].attach_type,
};
if (isAtLeastKernelVersion(4, 15, 0))
strlcpy(req.prog_name, cs[i].name.c_str(), sizeof(req.prog_name));
diff --git a/networksecurity/OWNERS b/networksecurity/OWNERS
new file mode 100644
index 0000000..1a4130a
--- /dev/null
+++ b/networksecurity/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 1479456
+
+sandrom@google.com
+tweek@google.com
diff --git a/networksecurity/framework/Android.bp b/networksecurity/framework/Android.bp
new file mode 100644
index 0000000..2b77926
--- /dev/null
+++ b/networksecurity/framework/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+package {
+ default_team: "trendy_team_platform_security",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+filegroup {
+ name: "framework-networksecurity-sources",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.aidl",
+ ],
+ path: "src",
+ visibility: [
+ "//packages/modules/Connectivity:__subpackages__",
+ ],
+}
diff --git a/networksecurity/framework/src/android/net/ct/CertificateTransparencyManager.java b/networksecurity/framework/src/android/net/ct/CertificateTransparencyManager.java
new file mode 100644
index 0000000..94521ae
--- /dev/null
+++ b/networksecurity/framework/src/android/net/ct/CertificateTransparencyManager.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.ct;
+
+import android.annotation.FlaggedApi;
+import android.annotation.SystemService;
+
+import com.android.net.ct.flags.Flags;
+
+/**
+ * Provides the primary API for the Certificate Transparency Manager.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_CERTIFICATE_TRANSPARENCY_SERVICE)
+@SystemService(CertificateTransparencyManager.SERVICE_NAME)
+public final class CertificateTransparencyManager {
+
+ public static final String SERVICE_NAME = "certificate_transparency";
+
+ /**
+ * Creates a new CertificateTransparencyManager instance.
+ *
+ * @hide
+ */
+ public CertificateTransparencyManager() {}
+}
diff --git a/networksecurity/framework/src/android/net/ct/ICertificateTransparencyManager.aidl b/networksecurity/framework/src/android/net/ct/ICertificateTransparencyManager.aidl
new file mode 100644
index 0000000..b5bce7f
--- /dev/null
+++ b/networksecurity/framework/src/android/net/ct/ICertificateTransparencyManager.aidl
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.ct;
+
+/**
+* Interface for communicating with CertificateTransparencyService.
+* @hide
+*/
+interface ICertificateTransparencyManager {}
diff --git a/networksecurity/service/Android.bp b/networksecurity/service/Android.bp
new file mode 100644
index 0000000..66d201a
--- /dev/null
+++ b/networksecurity/service/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package {
+ default_team: "trendy_team_platform_security",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+// Main lib for Certificate Transparency services.
+java_library {
+ name: "service-networksecurity-pre-jarjar",
+ defaults: ["framework-system-server-module-defaults"],
+ visibility: ["//packages/modules/Connectivity:__subpackages__"],
+
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ libs: [
+ "framework-connectivity-pre-jarjar",
+ "service-connectivity-pre-jarjar",
+ ],
+
+ // This is included in service-connectivity which is 30+
+ // TODO (b/293613362): allow APEXes to have service jars with higher min_sdk than the APEX
+ // (service-connectivity is only used on 31+) and use 31 here
+ min_sdk_version: "30",
+ sdk_version: "system_server_current",
+ apex_available: ["com.android.tethering"],
+}
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
new file mode 100644
index 0000000..8c53bf7
--- /dev/null
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.net.ct;
+
+import android.annotation.RequiresApi;
+import android.content.Context;
+import android.net.ct.ICertificateTransparencyManager;
+import android.os.Build;
+import android.util.Log;
+
+import com.android.net.ct.flags.Flags;
+import com.android.net.module.util.DeviceConfigUtils;
+
+/** Implementation of the Certificate Transparency service. */
+@RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+public class CertificateTransparencyService extends ICertificateTransparencyManager.Stub {
+
+ private static final String TAG = "CertificateTransparency";
+ private static final String CERTIFICATE_TRANSPARENCY_ENABLED =
+ "certificate_transparency_service_enabled";
+
+ /**
+ * @return true if the CertificateTransparency service is enabled.
+ */
+ public static boolean enabled(Context context) {
+ // TODO: replace isTetheringFeatureEnabled with CT namespace flag.
+ return DeviceConfigUtils.isTetheringFeatureEnabled(
+ context, CERTIFICATE_TRANSPARENCY_ENABLED)
+ && Flags.certificateTransparencyService();
+ }
+
+ /** Creates a new {@link CertificateTransparencyService} object. */
+ public CertificateTransparencyService(Context context) {}
+
+ /**
+ * Called by {@link com.android.server.ConnectivityServiceInitializer}.
+ *
+ * @see com.android.server.SystemService#onBootPhase
+ */
+ public void onBootPhase(int phase) {
+ Log.d(TAG, "CertificateTransparencyService#onBootPhase " + phase);
+ }
+}
diff --git a/service-t/Android.bp b/service-t/Android.bp
index 779f354..e00b7cf 100644
--- a/service-t/Android.bp
+++ b/service-t/Android.bp
@@ -59,6 +59,7 @@
"framework-wifi",
"service-connectivity-pre-jarjar",
"service-nearby-pre-jarjar",
+ "service-networksecurity-pre-jarjar",
"service-thread-pre-jarjar",
service_remoteauth_pre_jarjar_lib,
"ServiceConnectivityResources",
diff --git a/service-t/src/com/android/server/ConnectivityServiceInitializer.java b/service-t/src/com/android/server/ConnectivityServiceInitializer.java
index 1ac2f6e..5d23fdc 100644
--- a/service-t/src/com/android/server/ConnectivityServiceInitializer.java
+++ b/service-t/src/com/android/server/ConnectivityServiceInitializer.java
@@ -28,6 +28,7 @@
import com.android.server.ethernet.EthernetService;
import com.android.server.ethernet.EthernetServiceImpl;
import com.android.server.nearby.NearbyService;
+import com.android.server.net.ct.CertificateTransparencyService;
import com.android.server.thread.ThreadNetworkService;
/**
@@ -43,6 +44,7 @@
private final NearbyService mNearbyService;
private final EthernetServiceImpl mEthernetServiceImpl;
private final ThreadNetworkService mThreadNetworkService;
+ private final CertificateTransparencyService mCertificateTransparencyService;
public ConnectivityServiceInitializer(Context context) {
super(context);
@@ -55,6 +57,7 @@
mNsdService = createNsdService(context);
mNearbyService = createNearbyService(context);
mThreadNetworkService = createThreadNetworkService(context);
+ mCertificateTransparencyService = createCertificateTransparencyService(context);
}
@Override
@@ -111,6 +114,10 @@
if (mThreadNetworkService != null) {
mThreadNetworkService.onBootPhase(phase);
}
+
+ if (SdkLevel.isAtLeastV() && mCertificateTransparencyService != null) {
+ mCertificateTransparencyService.onBootPhase(phase);
+ }
}
/**
@@ -186,4 +193,13 @@
}
return new ThreadNetworkService(context);
}
+
+ /** Return CertificateTransparencyService instance if enable, otherwise null. */
+ @Nullable
+ private CertificateTransparencyService createCertificateTransparencyService(
+ final Context context) {
+ return SdkLevel.isAtLeastV() && CertificateTransparencyService.enabled(context)
+ ? new CertificateTransparencyService(context)
+ : null;
+ }
}
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 114cf2e..11343d2 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -74,12 +74,12 @@
import static com.android.net.module.util.DeviceConfigUtils.getDeviceConfigPropertyInt;
import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport;
import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT;
-import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_PERIODIC;
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_DUMPSYS;
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_FORCE_UPDATE;
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_GLOBAL_ALERT;
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_NETWORK_STATUS_CHANGED;
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_OPEN_SESSION;
+import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_PERIODIC;
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_RAT_CHANGED;
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_REG_CALLBACK;
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_REMOVE_UIDS;
@@ -242,13 +242,11 @@
// A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent
// deadlock.
private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4;
-
/** Flags to control detail level of poll event. */
private static final int FLAG_PERSIST_NETWORK = 0x1;
private static final int FLAG_PERSIST_UID = 0x2;
private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
private static final int FLAG_PERSIST_FORCE = 0x100;
-
/**
* When global alert quota is high, wait for this delay before processing each polling,
* and do not schedule further polls once there is already one queued.
@@ -313,6 +311,12 @@
static final String TRAFFIC_STATS_CACHE_MAX_ENTRIES_NAME = "trafficstats_cache_max_entries";
static final int DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS = 1000;
static final int DEFAULT_TRAFFIC_STATS_CACHE_MAX_ENTRIES = 400;
+ /**
+ * The delay time between to network stats update intents.
+ * Added to fix intent spams (b/3115462)
+ */
+ @VisibleForTesting(visibility = PRIVATE)
+ static final int BROADCAST_NETWORK_STATS_UPDATED_DELAY_MS = 1000;
private final Context mContext;
private final NetworkStatsFactory mStatsFactory;
@@ -385,6 +389,7 @@
long getXtPersistBytes(long def);
long getUidPersistBytes(long def);
long getUidTagPersistBytes(long def);
+ long getBroadcastNetworkStatsUpdateDelayMs();
}
private final Object mStatsLock = new Object();
@@ -469,15 +474,36 @@
private long mLastStatsSessionPoll;
+ /**
+ * The timestamp of the most recent network stats broadcast.
+ *
+ * Note that this time could be in the past for completed broadcasts,
+ * or in the future for scheduled broadcasts.
+ *
+ * It is initialized to {@code Long.MIN_VALUE} to ensure that the first broadcast request
+ * is fulfilled immediately, regardless of the delay time.
+ *
+ * This value is used to enforce rate limiting on intents, preventing intent spam.
+ */
+ @GuardedBy("mStatsLock")
+ private long mLatestNetworkStatsUpdatedBroadcastScheduledTime = Long.MIN_VALUE;
+
+
private final TrafficStatsRateLimitCache mTrafficStatsTotalCache;
private final TrafficStatsRateLimitCache mTrafficStatsIfaceCache;
private final TrafficStatsRateLimitCache mTrafficStatsUidCache;
static final String TRAFFICSTATS_RATE_LIMIT_CACHE_ENABLED_FLAG =
"trafficstats_rate_limit_cache_enabled_flag";
+ static final String BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG =
+ "broadcast_network_stats_updated_rate_limit_enabled_flag";
private final boolean mAlwaysUseTrafficStatsRateLimitCache;
private final int mTrafficStatsRateLimitCacheExpiryDuration;
private final int mTrafficStatsRateLimitCacheMaxEntries;
+ private final boolean mBroadcastNetworkStatsUpdatedRateLimitEnabled;
+
+
+
private final Object mOpenSessionCallsLock = new Object();
/**
@@ -669,6 +695,8 @@
mAlwaysUseTrafficStatsRateLimitCache =
mDeps.alwaysUseTrafficStatsRateLimitCache(mContext);
+ mBroadcastNetworkStatsUpdatedRateLimitEnabled =
+ mDeps.enabledBroadcastNetworkStatsUpdatedRateLimiting(mContext);
mTrafficStatsRateLimitCacheExpiryDuration =
mDeps.getTrafficStatsRateLimitCacheExpiryDuration();
mTrafficStatsRateLimitCacheMaxEntries =
@@ -696,6 +724,15 @@
@VisibleForTesting
public static class Dependencies {
/**
+ * Get broadcast network stats updated delay time in ms
+ * @return
+ */
+ @NonNull
+ public long getBroadcastNetworkStatsUpdateDelayMs() {
+ return BROADCAST_NETWORK_STATS_UPDATED_DELAY_MS;
+ }
+
+ /**
* Get legacy platform stats directory.
*/
@NonNull
@@ -927,6 +964,17 @@
}
/**
+ * Get whether broadcast network stats update rate limiting is enabled.
+ *
+ * This method should only be called once in the constructor,
+ * to ensure that the code does not need to deal with flag values changing at runtime.
+ */
+ public boolean enabledBroadcastNetworkStatsUpdatedRateLimiting(Context ctx) {
+ return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(
+ ctx, BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG);
+ }
+
+ /**
* Get whether TrafficStats rate-limit cache is always applied.
*
* This method should only be called once in the constructor,
@@ -2645,8 +2693,22 @@
performSampleLocked();
}
- // finally, dispatch updated event to any listeners
- mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED));
+ // Dispatch updated event to listeners, preventing intent spamming
+ // (b/343844995) possibly from abnormal modem RAT changes or misbehaving
+ // app calls (see NetworkStatsEventLogger#POLL_REASON_* for possible reasons).
+ // If no broadcasts are scheduled, use the time of the last broadcast
+ // to schedule the next one ASAP.
+ if (!mBroadcastNetworkStatsUpdatedRateLimitEnabled) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED));
+ } else if (mLatestNetworkStatsUpdatedBroadcastScheduledTime < SystemClock.uptimeMillis()) {
+ mLatestNetworkStatsUpdatedBroadcastScheduledTime = Math.max(
+ mLatestNetworkStatsUpdatedBroadcastScheduledTime
+ + mSettings.getBroadcastNetworkStatsUpdateDelayMs(),
+ SystemClock.uptimeMillis()
+ );
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED),
+ mLatestNetworkStatsUpdatedBroadcastScheduledTime);
+ }
Trace.traceEnd(TRACE_TAG_NETWORK);
}
@@ -3605,6 +3667,11 @@
public long getUidTagPersistBytes(long def) {
return def;
}
+
+ @Override
+ public long getBroadcastNetworkStatsUpdateDelayMs() {
+ return BROADCAST_NETWORK_STATS_UPDATED_DELAY_MS;
+ }
}
// TODO: Read stats by using BpfNetMapsReader.
diff --git a/service/Android.bp b/service/Android.bp
index 1a0e045..c68f0b8 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -206,6 +206,7 @@
},
visibility: [
"//packages/modules/Connectivity/service-t",
+ "//packages/modules/Connectivity/networksecurity:__subpackages__",
"//packages/modules/Connectivity/tests:__subpackages__",
"//packages/modules/Connectivity/thread/service:__subpackages__",
"//packages/modules/Connectivity/thread/tests:__subpackages__",
@@ -247,6 +248,7 @@
"service-connectivity-pre-jarjar",
"service-connectivity-tiramisu-pre-jarjar",
"service-nearby-pre-jarjar",
+ "service-networksecurity-pre-jarjar",
service_remoteauth_pre_jarjar_lib,
"service-thread-pre-jarjar",
],
@@ -315,6 +317,7 @@
":framework-connectivity-jarjar-rules",
":service-connectivity-jarjar-gen",
":service-nearby-jarjar-gen",
+ ":service-networksecurity-jarjar-gen",
":service-remoteauth-jarjar-gen",
":service-thread-jarjar-gen",
],
@@ -404,6 +407,24 @@
visibility: ["//visibility:private"],
}
+java_genrule {
+ name: "service-networksecurity-jarjar-gen",
+ tool_files: [
+ ":service-networksecurity-pre-jarjar{.jar}",
+ "jarjar-excludes.txt",
+ ],
+ tools: [
+ "jarjar-rules-generator",
+ ],
+ out: ["service_ct_jarjar_rules.txt"],
+ cmd: "$(location jarjar-rules-generator) " +
+ "$(location :service-networksecurity-pre-jarjar{.jar}) " +
+ "--prefix com.android.server.net.ct " +
+ "--excludes $(location jarjar-excludes.txt) " +
+ "--output $(out)",
+ visibility: ["//visibility:private"],
+}
+
genrule {
name: "statslog-connectivity-java-gen",
tools: ["stats-log-api-gen"],
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index c141b73..ed0670d 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -450,6 +450,7 @@
visibility: ["//packages/modules/Connectivity/service-t"],
}
+// net-utils-framework-connectivity is only for framework-connectivity.
java_library {
name: "net-utils-framework-connectivity",
srcs: [
@@ -462,8 +463,7 @@
"//apex_available:platform",
],
visibility: [
- "//packages/modules/Connectivity:__subpackages__",
- "//packages/modules/NetworkStack:__subpackages__",
+ "//packages/modules/Connectivity/framework",
],
libs: [
"androidx.annotation_annotation",
@@ -502,10 +502,6 @@
"com.android.tethering",
"//apex_available:platform",
],
- visibility: [
- "//packages/modules/CaptivePortalLogin:__subpackages__",
- "//packages/modules/Connectivity:__subpackages__",
- ],
defaults_visibility: [
"//visibility:private",
],
@@ -515,6 +511,7 @@
},
}
+// net-utils-service-connectivity is only for service-connectivity.
java_library {
name: "net-utils-service-connectivity",
srcs: [
@@ -528,6 +525,10 @@
],
defaults: ["net-utils-non-bootclasspath-defaults"],
jarjar_rules: "jarjar-rules-shared.txt",
+ visibility: [
+ "//packages/modules/Connectivity/service",
+ "//packages/modules/Connectivity/staticlibs/tests/unit",
+ ],
}
java_library {
@@ -538,6 +539,10 @@
],
defaults: ["net-utils-non-bootclasspath-defaults"],
jarjar_rules: "jarjar-rules-shared.txt",
+ visibility: [
+ "//packages/modules/CaptivePortalLogin:__subpackages__",
+ "//packages/modules/Connectivity/Tethering",
+ ],
}
aidl_interface {
diff --git a/staticlibs/tests/unit/src/com/android/testutils/NetworkStatsUtilsTest.kt b/staticlibs/tests/unit/src/com/android/testutils/NetworkStatsUtilsTest.kt
new file mode 100644
index 0000000..2f436cd
--- /dev/null
+++ b/staticlibs/tests/unit/src/com/android/testutils/NetworkStatsUtilsTest.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.testutils
+
+import android.net.NetworkStats
+import android.net.NetworkStats.DEFAULT_NETWORK_NO
+import android.net.NetworkStats.METERED_NO
+import android.net.NetworkStats.ROAMING_NO
+import android.net.NetworkStats.SET_DEFAULT
+import android.net.NetworkStats.TAG_NONE
+import android.os.Build
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+private const val TEST_IFACE = "test0"
+private const val TEST_IFACE2 = "test2"
+private const val TEST_START = 1194220800000L
+
+@RunWith(JUnit4::class)
+class NetworkStatsUtilsTest {
+ // This is a unit test for a test utility that uses R APIs
+ @Rule @JvmField
+ val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q)
+
+ @Test
+ fun testOrderInsensitiveEquals() {
+ val testEntry = arrayOf(
+ NetworkStats.Entry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 128L, 8L, 0L, 2L, 20L),
+ NetworkStats.Entry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
+ )
+
+ // Verify equals of empty stats regardless of initial capacity.
+ val red = NetworkStats(TEST_START, 0)
+ val blue = NetworkStats(TEST_START, 1)
+ assertTrue(orderInsensitiveEquals(red, blue))
+ assertTrue(orderInsensitiveEquals(blue, red))
+
+ // Verify not equal.
+ red.combineValues(testEntry[1])
+ blue.combineValues(testEntry[0]).combineValues(testEntry[1])
+ assertFalse(orderInsensitiveEquals(red, blue))
+ assertFalse(orderInsensitiveEquals(blue, red))
+
+ // Verify equals even if the order of entries are not the same.
+ red.combineValues(testEntry[0])
+ assertTrue(orderInsensitiveEquals(red, blue))
+ assertTrue(orderInsensitiveEquals(blue, red))
+ }
+}
diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp
index 4749e75..8c71a91 100644
--- a/staticlibs/testutils/Android.bp
+++ b/staticlibs/testutils/Android.bp
@@ -42,7 +42,6 @@
"net-utils-device-common-struct",
"net-utils-device-common-struct-base",
"net-utils-device-common-wear",
- "net-utils-framework-connectivity",
"modules-utils-build_system",
],
lint: {
diff --git a/tests/common/java/android/net/netstats/NetworkStatsApiTest.kt b/tests/common/java/android/net/netstats/NetworkStatsApiTest.kt
index 8cef6aa..17f5e96 100644
--- a/tests/common/java/android/net/netstats/NetworkStatsApiTest.kt
+++ b/tests/common/java/android/net/netstats/NetworkStatsApiTest.kt
@@ -28,18 +28,26 @@
import android.net.NetworkStats.SET_DEFAULT
import android.net.NetworkStats.SET_FOREGROUND
import android.net.NetworkStats.TAG_NONE
+import android.os.Build
import androidx.test.filters.SmallTest
+import com.android.testutils.ConnectivityModuleTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
+import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.assertNetworkStatsEquals
import com.android.testutils.assertParcelingIsLossless
import kotlin.test.assertEquals
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-@RunWith(JUnit4::class)
+@DevSdkIgnoreRunner.MonitorThreadLeak
+@RunWith(DevSdkIgnoreRunner::class)
@SmallTest
class NetworkStatsApiTest {
+ @get:Rule
+ val ignoreRule = DevSdkIgnoreRule()
private val testStatsEmpty = NetworkStats(0L, 0)
// Note that these variables need to be initialized outside of constructor, initialize
@@ -49,6 +57,7 @@
// be merged if performing add on these 2 stats.
private lateinit var testStats1: NetworkStats
private lateinit var testStats2: NetworkStats
+ private lateinit var expectedEntriesInStats2: List<Entry>
// This is a result of adding stats1 and stats2, while the merging of common key items is
// subject to test later, this should not be initialized with for a loop to add stats1
@@ -84,19 +93,23 @@
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0))
assertEquals(8, testStats1.size())
- testStats2 = NetworkStats(0L, 0)
- // Entries which are common for set1 and set2.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
- .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7))
- .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0))
- // Entry which only appears in set2.
- .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
+ expectedEntriesInStats2 = listOf(
+ // Entries which are common for set1 and set2.
+ Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1),
+ Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45),
+ Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7),
+ Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0),
+ // Entry which only appears in set2.
+ Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
+ testStats2 = NetworkStats(0L, 5)
+ for (entry in expectedEntriesInStats2) {
+ testStats2 = testStats2.addEntry(entry)
+ }
assertEquals(5, testStats2.size())
testStats3 = NetworkStats(0L, 9)
@@ -125,18 +138,6 @@
@Test
fun testAddEntry() {
- val expectedEntriesInStats2 = arrayOf(
- Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1),
- Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45),
- Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7),
- Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0),
- Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
-
// While testStats* are already initialized with addEntry, verify content added
// matches expectation.
for (i in expectedEntriesInStats2.indices) {
@@ -150,6 +151,27 @@
assertEquals(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16, -2, 9, 1, 9),
stats.getValues(3, null))
+
+ // Verify the original ststs object is not altered.
+ for (i in expectedEntriesInStats2.indices) {
+ val entry = testStats2.getValues(i, null)
+ assertEquals(expectedEntriesInStats2[i], entry)
+ }
+ }
+
+ @ConnectivityModuleTest
+ @IgnoreUpTo(Build.VERSION_CODES.S_V2) // Mainlined NetworkStats only runs on T+
+ @Test
+ fun testAddEntries() {
+ val baseStats = NetworkStats(0L, 1)
+ .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12, -5, 7, 0, 9))
+ val statsUnderTest = baseStats.addEntries(expectedEntriesInStats2)
+ // Assume the correctness of addEntry is verified in other tests.
+ val expectedStats = testStats2
+ .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12, -5, 7, 0, 9))
+ assertNetworkStatsEquals(expectedStats, statsUnderTest)
}
@Test
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 9458460..88c2d5a 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -206,6 +206,7 @@
import com.android.networkstack.apishim.common.ConnectivityManagerShim;
import com.android.testutils.AutoReleaseNetworkCallbackRule;
import com.android.testutils.CompatUtil;
+import com.android.testutils.ConnectUtil;
import com.android.testutils.ConnectivityModuleTest;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
@@ -2942,20 +2943,10 @@
// This may also apply to wifi in principle, but in practice methods that mock validation
// URL all disconnect wifi forcefully anyway, so don't wait for wifi to validate.
if (mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) {
- ensureValidatedNetwork(makeCellNetworkRequest());
+ new ConnectUtil(mContext).ensureCellularValidated();
}
}
- private void ensureValidatedNetwork(NetworkRequest request) {
- final TestableNetworkCallback cb = new TestableNetworkCallback();
- mCm.registerNetworkCallback(request, cb);
- cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
- NETWORK_CALLBACK_TIMEOUT_MS,
- entry -> ((CallbackEntry.CapabilitiesChanged) entry).getCaps()
- .hasCapability(NET_CAPABILITY_VALIDATED));
- mCm.unregisterNetworkCallback(cb);
- }
-
@AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
@Test
public void testAcceptPartialConnectivity_validatedNetwork() throws Exception {
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 7e0a225..3d2f389 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -69,6 +69,8 @@
import static com.android.server.net.NetworkStatsEventLogger.POLL_REASON_RAT_CHANGED;
import static com.android.server.net.NetworkStatsEventLogger.PollEvent.pollReasonNameOf;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
+import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
+import static com.android.server.net.NetworkStatsService.BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG;
import static com.android.server.net.NetworkStatsService.DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS;
import static com.android.server.net.NetworkStatsService.DEFAULT_TRAFFIC_STATS_CACHE_MAX_ENTRIES;
import static com.android.server.net.NetworkStatsService.NETSTATS_FASTDATAINPUT_FALLBACKS_COUNTER_NAME;
@@ -82,6 +84,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalMatchers.aryEq;
@@ -101,8 +104,10 @@
import android.annotation.NonNull;
import android.app.AlarmManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -138,6 +143,7 @@
import android.provider.Settings;
import android.system.ErrnoException;
import android.telephony.TelephonyManager;
+import android.testing.TestableLooper;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
@@ -150,6 +156,7 @@
import com.android.connectivity.resources.R;
import com.android.internal.util.FileRotator;
import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.net.module.util.ArrayTrackRecord;
import com.android.net.module.util.BpfDump;
import com.android.net.module.util.IBpfMap;
import com.android.net.module.util.LocationPermissionChecker;
@@ -618,6 +625,12 @@
}
@Override
+ public boolean enabledBroadcastNetworkStatsUpdatedRateLimiting(Context ctx) {
+ return mFeatureFlags.getOrDefault(
+ BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG, true);
+ }
+
+ @Override
public int getTrafficStatsRateLimitCacheExpiryDuration() {
return DEFAULT_TRAFFIC_STATS_CACHE_EXPIRY_DURATION_MS;
}
@@ -2617,6 +2630,8 @@
private void mockDefaultSettings() throws Exception {
mockSettings(HOUR_IN_MILLIS, WEEK_IN_MILLIS);
+ mSettings.setBroadcastNetworkStatsUpdateDelayMs(
+ NetworkStatsService.BROADCAST_NETWORK_STATS_UPDATED_DELAY_MS);
}
private void mockSettings(long bucketDuration, long deleteAge) {
@@ -2631,6 +2646,8 @@
@NonNull
private volatile Config mConfig;
private final AtomicBoolean mCombineSubtypeEnabled = new AtomicBoolean();
+ private long mBroadcastNetworkStatsUpdateDelayMs =
+ NetworkStatsService.BROADCAST_NETWORK_STATS_UPDATED_DELAY_MS;
TestNetworkStatsSettings(long bucketDuration, long deleteAge) {
mConfig = new Config(bucketDuration, deleteAge, deleteAge);
@@ -2693,6 +2710,15 @@
public boolean getAugmentEnabled() {
return false;
}
+
+ @Override
+ public long getBroadcastNetworkStatsUpdateDelayMs() {
+ return mBroadcastNetworkStatsUpdateDelayMs;
+ }
+
+ public void setBroadcastNetworkStatsUpdateDelayMs(long broadcastDelay) {
+ mBroadcastNetworkStatsUpdateDelayMs = broadcastDelay;
+ }
}
private void assertStatsFilesExist(boolean exist) {
@@ -3064,4 +3090,91 @@
final String dump = getDump();
assertDumpContains(dump, "Log for testing");
}
+
+ private static class TestNetworkStatsUpdatedReceiver extends BroadcastReceiver {
+ private final ArrayTrackRecord<Intent>.ReadHead mHistory;
+
+ TestNetworkStatsUpdatedReceiver() {
+ mHistory = (new ArrayTrackRecord<Intent>()).newReadHead();
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mHistory.add(intent);
+ }
+
+ /**
+ * Assert no broadcast intent is received in blocking manner
+ */
+ public void assertNoBroadcastIntentReceived() {
+ assertNull(mHistory.peek());
+ }
+
+ /**
+ * Assert an intent is received and remove it from queue
+ */
+ public void assertBroadcastIntentReceived() {
+ assertNotNull(mHistory.poll(WAIT_TIMEOUT, number -> true));
+ }
+ }
+
+ @FeatureFlag(name = BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG)
+ @Test
+ public void testNetworkStatsUpdatedIntentSpam_rateLimitOn() throws Exception {
+ // Set the update delay long enough that messages won't be processed before unblocked
+ // Set a short time to test the behavior before reaching delay.
+ // Constraint: test running time < toleranceMs < update delay time
+ mSettings.setBroadcastNetworkStatsUpdateDelayMs(100_000L);
+ final long toleranceMs = 5000;
+
+ final TestableLooper mTestableLooper = new TestableLooper(mHandlerThread.getLooper());
+ final TestNetworkStatsUpdatedReceiver receiver = new TestNetworkStatsUpdatedReceiver();
+ mServiceContext.registerReceiver(receiver, new IntentFilter(ACTION_NETWORK_STATS_UPDATED));
+
+ try {
+ // Test that before anything, the intent is delivered immediately
+ mService.forceUpdate();
+ mTestableLooper.processAllMessages();
+ receiver.assertBroadcastIntentReceived();
+ receiver.assertNoBroadcastIntentReceived();
+
+ // Test that the next two intents results in exactly one intent delivered
+ for (int i = 0; i < 2; i++) {
+ mService.forceUpdate();
+ }
+ // Test that the delay depends on our set value
+ mTestableLooper.moveTimeForward(mSettings.getBroadcastNetworkStatsUpdateDelayMs()
+ - toleranceMs);
+ mTestableLooper.processAllMessages();
+ receiver.assertNoBroadcastIntentReceived();
+
+ // Unblock messages and test that the second and third update
+ // is broadcasted right after the delay
+ mTestableLooper.moveTimeForward(toleranceMs);
+ mTestableLooper.processAllMessages();
+ receiver.assertBroadcastIntentReceived();
+ receiver.assertNoBroadcastIntentReceived();
+
+ } finally {
+ mTestableLooper.destroy();
+ }
+ }
+
+ @FeatureFlag(name = BROADCAST_NETWORK_STATS_UPDATED_RATE_LIMIT_ENABLED_FLAG, enabled = false)
+ @Test
+ public void testNetworkStatsUpdatedIntentSpam_rateLimitOff() throws Exception {
+ // Set the update delay long enough to ensure that messages are processed
+ // despite the rate limit.
+ mSettings.setBroadcastNetworkStatsUpdateDelayMs(100_000L);
+
+ final TestNetworkStatsUpdatedReceiver receiver = new TestNetworkStatsUpdatedReceiver();
+ mServiceContext.registerReceiver(receiver, new IntentFilter(ACTION_NETWORK_STATS_UPDATED));
+
+ for (int i = 0; i < 2; i++) {
+ mService.forceUpdate();
+ waitForIdle();
+ receiver.assertBroadcastIntentReceived();
+ }
+ receiver.assertNoBroadcastIntentReceived();
+ }
}
diff --git a/thread/framework/java/android/net/thread/ChannelMaxPower.aidl b/thread/framework/java/android/net/thread/ChannelMaxPower.aidl
index bcda8a8..abc00b9 100644
--- a/thread/framework/java/android/net/thread/ChannelMaxPower.aidl
+++ b/thread/framework/java/android/net/thread/ChannelMaxPower.aidl
@@ -16,11 +16,11 @@
package android.net.thread;
- /**
- * Mapping from a channel to its max power.
- *
- * {@hide}
- */
+/**
+ * Mapping from a channel to its max power.
+ *
+ * {@hide}
+ */
parcelable ChannelMaxPower {
int channel; // The Thread radio channel.
int maxPower; // The max power in the unit of 0.01dBm. Passing INT16_MAX(32767) will
diff --git a/thread/framework/java/android/net/thread/IOperationalDatasetCallback.aidl b/thread/framework/java/android/net/thread/IOperationalDatasetCallback.aidl
index b576b33..3fece65 100644
--- a/thread/framework/java/android/net/thread/IOperationalDatasetCallback.aidl
+++ b/thread/framework/java/android/net/thread/IOperationalDatasetCallback.aidl
@@ -23,6 +23,8 @@
* @hide
*/
oneway interface IOperationalDatasetCallback {
- void onActiveOperationalDatasetChanged(in @nullable ActiveOperationalDataset activeOpDataset);
- void onPendingOperationalDatasetChanged(in @nullable PendingOperationalDataset pendingOpDataset);
+ void onActiveOperationalDatasetChanged(
+ in @nullable ActiveOperationalDataset activeOpDataset);
+ void onPendingOperationalDatasetChanged(
+ in @nullable PendingOperationalDataset pendingOpDataset);
}
diff --git a/thread/framework/java/android/net/thread/IThreadNetworkController.aidl b/thread/framework/java/android/net/thread/IThreadNetworkController.aidl
index f50de74..b7f68c9 100644
--- a/thread/framework/java/android/net/thread/IThreadNetworkController.aidl
+++ b/thread/framework/java/android/net/thread/IThreadNetworkController.aidl
@@ -28,9 +28,9 @@
import android.net.thread.ThreadConfiguration;
/**
-* Interface for communicating with ThreadNetworkControllerService.
-* @hide
-*/
+ * Interface for communicating with ThreadNetworkControllerService.
+ * @hide
+ */
interface IThreadNetworkController {
void registerStateCallback(in IStateCallback callback);
void unregisterStateCallback(in IStateCallback callback);
@@ -38,10 +38,12 @@
void unregisterOperationalDatasetCallback(in IOperationalDatasetCallback callback);
void join(in ActiveOperationalDataset activeOpDataset, in IOperationReceiver receiver);
- void scheduleMigration(in PendingOperationalDataset pendingOpDataset, in IOperationReceiver receiver);
+ void scheduleMigration(
+ in PendingOperationalDataset pendingOpDataset, in IOperationReceiver receiver);
void leave(in IOperationReceiver receiver);
- void setTestNetworkAsUpstream(in String testNetworkInterfaceName, in IOperationReceiver receiver);
+ void setTestNetworkAsUpstream(
+ in String testNetworkInterfaceName, in IOperationReceiver receiver);
void setChannelMaxPowers(in ChannelMaxPower[] channelMaxPowers, in IOperationReceiver receiver);
int getThreadVersion();
diff --git a/thread/framework/java/android/net/thread/IThreadNetworkManager.aidl b/thread/framework/java/android/net/thread/IThreadNetworkManager.aidl
index 0e394b1..b63cd72 100644
--- a/thread/framework/java/android/net/thread/IThreadNetworkManager.aidl
+++ b/thread/framework/java/android/net/thread/IThreadNetworkManager.aidl
@@ -19,9 +19,9 @@
import android.net.thread.IThreadNetworkController;
/**
-* Interface for communicating with ThreadNetworkService.
-* @hide
-*/
+ * Interface for communicating with ThreadNetworkService.
+ * @hide
+ */
interface IThreadNetworkManager {
List<IThreadNetworkController> getAllThreadNetworkControllers();
}
diff --git a/thread/scripts/make-pretty.sh b/thread/scripts/make-pretty.sh
index c176bfa..e012d41 100755
--- a/thread/scripts/make-pretty.sh
+++ b/thread/scripts/make-pretty.sh
@@ -1,9 +1,35 @@
#!/usr/bin/env bash
-SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+ANDROID_ROOT_DIR=$(
+ while [ ! -d ".repo" ] && [ "$PWD" != "/" ]; do cd ..; done
+ pwd
+)
-GOOGLE_JAVA_FORMAT=$SCRIPT_DIR/../../../../../prebuilts/tools/common/google-java-format/google-java-format
-ANDROID_BP_FORMAT=$SCRIPT_DIR/../../../../../prebuilts/build-tools/linux-x86/bin/bpfmt
+if [ ! -d "$ANDROID_ROOT_DIR/.repo" ]; then
+ echo "Error: The script has to run in an Android repo checkout"
+ exit 1
+fi
-$GOOGLE_JAVA_FORMAT --aosp -i $(find $SCRIPT_DIR/../ -name "*.java")
-$ANDROID_BP_FORMAT -w $(find $SCRIPT_DIR/../ -name "*.bp")
+GOOGLE_JAVA_FORMAT=$ANDROID_ROOT_DIR/prebuilts/tools/common/google-java-format/google-java-format
+ANDROID_BP_FORMAT=$ANDROID_ROOT_DIR/prebuilts/build-tools/linux-x86/bin/bpfmt
+AIDL_FORMAT=$ANDROID_ROOT_DIR/system/tools/aidl/aidl-format.sh
+
+CONNECTIVITY_DIR=$ANDROID_ROOT_DIR/packages/modules/Connectivity
+OPENTHREAD_DIR=$ANDROID_ROOT_DIR/external/openthread
+OTBR_POSIX_DIR=$ANDROID_ROOT_DIR/external/ot-br-posix
+
+ALLOWED_CODE_DIRS=($CONNECTIVITY_DIR $OPENTHREAD_DIR $OTBR_POSIX_DIR)
+CODE_DIR=$(git rev-parse --show-toplevel)
+
+if [[ ! " ${ALLOWED_CODE_DIRS[@]} " =~ " ${CODE_DIR} " ]]; then
+ echo "Error: The script has to run in the Git project Connectivity, openthread or ot-br-posix"
+ exit 1
+fi
+
+if [[ $CODE_DIR == $CONNECTIVITY_DIR ]]; then
+ CODE_DIR=$CODE_DIR"/thread"
+fi
+
+$GOOGLE_JAVA_FORMAT --aosp -i $(find $CODE_DIR -name "*.java")
+$ANDROID_BP_FORMAT -w $(find $CODE_DIR -name "*.bp")
+$AIDL_FORMAT -w $(find $CODE_DIR -name "*.aidl")