From e964543988a8c783da652223d818f20160979d03 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 25 Mar 2022 11:05:20 +0000 Subject: [PATCH] Move ConnectivityT to packages/modules Delete the files that are moved with history to packages/modules/Connectivity. Bug: 222234190 Test: TH Ignore-AOSP-First: Move with history done per-branch Merged-In: I399d2bb259d50916c575e59621ddfaf798affc5c Change-Id: I4ec993d98b084bc73a57131fa632190a050c93cb --- packages/ConnectivityT/OWNERS | 5 - packages/ConnectivityT/framework-t/Android.bp | 205 -- .../aidl-export/android/net/NetworkStats.aidl | 19 - .../android/net/NetworkTemplate.aidl | 19 - .../android/net/nsd/NsdServiceInfo.aidl | 19 - .../jni/android_net_TrafficStats.cpp | 46 - .../ConnectivityT/framework-t/jni/onload.cpp | 39 - .../src/android/app/usage/NetworkStats.java | 742 ----- .../app/usage/NetworkStatsManager.java | 1181 -------- ...nectivityFrameworkInitializerTiramisu.java | 82 - .../src/android/net/DataUsageRequest.aidl | 19 - .../src/android/net/DataUsageRequest.java | 112 - .../src/android/net/EthernetManager.java | 729 ----- .../EthernetNetworkManagementException.aidl | 19 - .../EthernetNetworkManagementException.java | 73 - .../android/net/EthernetNetworkSpecifier.java | 102 - .../net/EthernetNetworkUpdateRequest.aidl | 19 - .../net/EthernetNetworkUpdateRequest.java | 185 -- .../src/android/net/IEthernetManager.aidl | 50 - .../android/net/IEthernetServiceListener.aidl | 27 - .../src/android/net/IIpSecService.aidl | 78 - .../net/INetworkInterfaceOutcomeReceiver.aidl | 25 - .../src/android/net/INetworkStatsService.aidl | 104 - .../src/android/net/INetworkStatsSession.aidl | 70 - .../net/ITetheredInterfaceCallback.aidl | 23 - .../src/android/net/IpSecAlgorithm.java | 491 ---- .../src/android/net/IpSecConfig.aidl | 20 - .../src/android/net/IpSecConfig.java | 358 --- .../src/android/net/IpSecManager.java | 1065 ------- .../src/android/net/IpSecSpiResponse.aidl | 20 - .../src/android/net/IpSecSpiResponse.java | 78 - .../src/android/net/IpSecTransform.java | 405 --- .../android/net/IpSecTransformResponse.aidl | 20 - .../android/net/IpSecTransformResponse.java | 74 - .../net/IpSecTunnelInterfaceResponse.aidl | 20 - .../net/IpSecTunnelInterfaceResponse.java | 79 - .../android/net/IpSecUdpEncapResponse.aidl | 20 - .../android/net/IpSecUdpEncapResponse.java | 98 - .../src/android/net/NetworkIdentity.java | 594 ---- .../src/android/net/NetworkIdentitySet.java | 230 -- .../src/android/net/NetworkStateSnapshot.java | 192 -- .../src/android/net/NetworkStats.java | 1834 ------------ .../src/android/net/NetworkStatsAccess.java | 208 -- .../android/net/NetworkStatsCollection.java | 956 ------- .../src/android/net/NetworkStatsHistory.aidl | 19 - .../src/android/net/NetworkStatsHistory.java | 1162 -------- .../src/android/net/NetworkTemplate.java | 1119 -------- .../src/android/net/TrafficStats.java | 1148 -------- .../android/net/UnderlyingNetworkInfo.aidl | 19 - .../android/net/UnderlyingNetworkInfo.java | 135 - .../android/net/netstats/IUsageCallback.aidl | 29 - .../provider/INetworkStatsProvider.aidl | 28 - .../INetworkStatsProviderCallback.aidl | 32 - .../provider/NetworkStatsProvider.java | 232 -- .../src/android/net/nsd/INsdManager.aidl | 30 - .../android/net/nsd/INsdManagerCallback.aidl | 39 - .../android/net/nsd/INsdServiceConnector.aidl | 35 - .../src/android/net/nsd/NsdManager.java | 1083 ------- .../src/android/net/nsd/NsdServiceInfo.java | 418 --- packages/ConnectivityT/service/Android.bp | 156 - ...android_server_net_NetworkStatsFactory.cpp | 362 --- ...android_server_net_NetworkStatsService.cpp | 116 - packages/ConnectivityT/service/jni/onload.cpp | 38 - .../INativeDaemonConnectorCallbacks.java | 25 - .../src/com/android/server/IpSecService.java | 1878 ------------ .../android/server/NativeDaemonConnector.java | 704 ----- .../NativeDaemonConnectorException.java | 58 - .../com/android/server/NativeDaemonEvent.java | 267 -- .../server/NativeDaemonTimeoutException.java | 28 - .../src/com/android/server/NsdService.java | 1146 -------- .../server/net/BpfInterfaceMapUpdater.java | 139 - .../android/server/net/CookieTagMapKey.java | 33 - .../android/server/net/CookieTagMapValue.java | 37 - .../android/server/net/DelayedDiskWrite.java | 114 - .../android/server/net/InterfaceMapValue.java | 35 - .../com/android/server/net/IpConfigStore.java | 449 --- .../server/net/NetworkStatsFactory.java | 505 ---- .../server/net/NetworkStatsObservers.java | 451 --- .../server/net/NetworkStatsRecorder.java | 507 ---- .../server/net/NetworkStatsService.java | 2528 ----------------- .../net/NetworkStatsSubscriptionsMonitor.java | 246 -- .../com/android/server/net/StatsMapKey.java | 46 - .../com/android/server/net/StatsMapValue.java | 46 - .../android/server/net/UidStatsMapKey.java | 33 - .../server/NativeDaemonConnectorTest.java | 97 - .../android/server/net/IpConfigStoreTest.java | 159 -- 86 files changed, 26485 deletions(-) delete mode 100644 packages/ConnectivityT/OWNERS delete mode 100644 packages/ConnectivityT/framework-t/Android.bp delete mode 100644 packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkStats.aidl delete mode 100644 packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkTemplate.aidl delete mode 100644 packages/ConnectivityT/framework-t/aidl-export/android/net/nsd/NsdServiceInfo.aidl delete mode 100644 packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp delete mode 100644 packages/ConnectivityT/framework-t/jni/onload.cpp delete mode 100644 packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IIpSecService.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/netstats/IUsageCallback.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManager.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManagerCallback.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/nsd/INsdServiceConnector.aidl delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java delete mode 100644 packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java delete mode 100644 packages/ConnectivityT/service/Android.bp delete mode 100644 packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp delete mode 100644 packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp delete mode 100644 packages/ConnectivityT/service/jni/onload.cpp delete mode 100644 packages/ConnectivityT/service/src/com/android/server/INativeDaemonConnectorCallbacks.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/IpSecService.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnector.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnectorException.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/NativeDaemonEvent.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/NativeDaemonTimeoutException.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/NsdService.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/DelayedDiskWrite.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java delete mode 100644 packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java delete mode 100644 packages/ConnectivityT/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java delete mode 100644 packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java diff --git a/packages/ConnectivityT/OWNERS b/packages/ConnectivityT/OWNERS deleted file mode 100644 index adbcd4b5a36b6..0000000000000 --- a/packages/ConnectivityT/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -# OWNERS block for code move: b/222234190 -reminv@google.com - -# file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking -# per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp deleted file mode 100644 index bc278528570fa..0000000000000 --- a/packages/ConnectivityT/framework-t/Android.bp +++ /dev/null @@ -1,205 +0,0 @@ -// -// Copyright (C) 2021 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 { - // See: http://go/android-license-faq - default_applicable_licenses: ["Android-Apache-2.0"], -} - -// NetworkStats related libraries. - -filegroup { - name: "framework-connectivity-netstats-internal-sources", - srcs: [ - "src/android/app/usage/*.java", - "src/android/net/DataUsageRequest.*", - "src/android/net/INetworkStatsService.aidl", - "src/android/net/INetworkStatsSession.aidl", - "src/android/net/NetworkIdentity.java", - "src/android/net/NetworkIdentitySet.java", - "src/android/net/NetworkStateSnapshot.*", - "src/android/net/NetworkStats.*", - "src/android/net/NetworkStatsAccess.*", - "src/android/net/NetworkStatsCollection.*", - "src/android/net/NetworkStatsHistory.*", - "src/android/net/NetworkTemplate.*", - "src/android/net/TrafficStats.java", - "src/android/net/UnderlyingNetworkInfo.*", - "src/android/net/netstats/**/*.*", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -filegroup { - name: "framework-connectivity-netstats-aidl-export-sources", - srcs: [ - "aidl-export/android/net/NetworkStats.aidl", - "aidl-export/android/net/NetworkTemplate.aidl", - ], - path: "aidl-export", - visibility: [ - "//visibility:private", - ], -} - -filegroup { - name: "framework-connectivity-netstats-sources", - srcs: [ - ":framework-connectivity-netstats-internal-sources", - ":framework-connectivity-netstats-aidl-export-sources", - ], - visibility: [ - "//visibility:private", - ], -} - -// Nsd related libraries. - -filegroup { - name: "framework-connectivity-nsd-internal-sources", - srcs: [ - "src/android/net/nsd/*.aidl", - "src/android/net/nsd/*.java", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -filegroup { - name: "framework-connectivity-nsd-aidl-export-sources", - srcs: [ - "aidl-export/android/net/nsd/*.aidl", - ], - path: "aidl-export", - visibility: [ - "//visibility:private", - ], -} - -filegroup { - name: "framework-connectivity-nsd-sources", - srcs: [ - ":framework-connectivity-nsd-internal-sources", - ":framework-connectivity-nsd-aidl-export-sources", - ], - visibility: [ - "//visibility:private", - ], -} - -// IpSec related libraries. - -filegroup { - name: "framework-connectivity-ipsec-sources", - srcs: [ - "src/android/net/IIpSecService.aidl", - "src/android/net/IpSec*.*", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// Ethernet related libraries. - -filegroup { - name: "framework-connectivity-ethernet-sources", - srcs: [ - "src/android/net/EthernetManager.java", - "src/android/net/EthernetNetworkManagementException.java", - "src/android/net/EthernetNetworkManagementException.aidl", - "src/android/net/EthernetNetworkSpecifier.java", - "src/android/net/EthernetNetworkUpdateRequest.java", - "src/android/net/EthernetNetworkUpdateRequest.aidl", - "src/android/net/IEthernetManager.aidl", - "src/android/net/IEthernetServiceListener.aidl", - "src/android/net/INetworkInterfaceOutcomeReceiver.aidl", - "src/android/net/ITetheredInterfaceCallback.aidl", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// Connectivity-T common libraries. - -filegroup { - name: "framework-connectivity-tiramisu-internal-sources", - srcs: [ - "src/android/net/ConnectivityFrameworkInitializerTiramisu.java", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// TODO: remove this empty filegroup. -filegroup { - name: "framework-connectivity-tiramisu-sources", - srcs: [], - visibility: ["//frameworks/base"], -} - -filegroup { - name: "framework-connectivity-tiramisu-updatable-sources", - srcs: [ - ":framework-connectivity-ethernet-sources", - ":framework-connectivity-ipsec-sources", - ":framework-connectivity-netstats-sources", - ":framework-connectivity-nsd-sources", - ":framework-connectivity-tiramisu-internal-sources", - ], - visibility: [ - "//frameworks/base", - "//packages/modules/Connectivity:__subpackages__", - ], -} - -cc_library_shared { - name: "libframework-connectivity-tiramisu-jni", - min_sdk_version: "30", - cflags: [ - "-Wall", - "-Werror", - "-Wno-unused-parameter", - // Don't warn about S API usage even with - // min_sdk 30: the library is only loaded - // on S+ devices - "-Wno-unguarded-availability", - "-Wthread-safety", - ], - srcs: [ - "jni/android_net_TrafficStats.cpp", - "jni/onload.cpp", - ], - shared_libs: [ - "libandroid", - "liblog", - "libnativehelper", - ], - stl: "none", - apex_available: [ - "com.android.tethering", - ], -} diff --git a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkStats.aidl b/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkStats.aidl deleted file mode 100644 index d06ca65a3e0de..0000000000000 --- a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkStats.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2011, 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; - -parcelable NetworkStats; diff --git a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkTemplate.aidl b/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkTemplate.aidl deleted file mode 100644 index 3d37488d9881b..0000000000000 --- a/packages/ConnectivityT/framework-t/aidl-export/android/net/NetworkTemplate.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2011, 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; - -parcelable NetworkTemplate; diff --git a/packages/ConnectivityT/framework-t/aidl-export/android/net/nsd/NsdServiceInfo.aidl b/packages/ConnectivityT/framework-t/aidl-export/android/net/nsd/NsdServiceInfo.aidl deleted file mode 100644 index 657bdd1e8706b..0000000000000 --- a/packages/ConnectivityT/framework-t/aidl-export/android/net/nsd/NsdServiceInfo.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2021 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.nsd; - -@JavaOnlyStableParcelable parcelable NsdServiceInfo; \ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp b/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp deleted file mode 100644 index f3c58b112f0d3..0000000000000 --- a/packages/ConnectivityT/framework-t/jni/android_net_TrafficStats.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2022 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. - */ - -#include -#include -#include - -namespace android { - -static jint tagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor, jint tag, jint uid) { - int fd = AFileDescriptor_getFd(env, fileDescriptor); - if (fd == -1) return -EBADF; - return android_tag_socket_with_uid(fd, tag, uid); -} - -static jint untagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor) { - int fd = AFileDescriptor_getFd(env, fileDescriptor); - if (fd == -1) return -EBADF; - return android_untag_socket(fd); -} - -static const JNINativeMethod gMethods[] = { - /* name, signature, funcPtr */ - { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*) tagSocketFd }, - { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*) untagSocketFd }, -}; - -int register_android_net_TrafficStats(JNIEnv* env) { - return jniRegisterNativeMethods(env, "android/net/TrafficStats", gMethods, NELEM(gMethods)); -} - -}; // namespace android - diff --git a/packages/ConnectivityT/framework-t/jni/onload.cpp b/packages/ConnectivityT/framework-t/jni/onload.cpp deleted file mode 100644 index 1fb42c63477e4..0000000000000 --- a/packages/ConnectivityT/framework-t/jni/onload.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2022 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. - */ - -#define LOG_TAG "FrameworkConnectivityJNI" - -#include -#include - -namespace android { - -int register_android_net_TrafficStats(JNIEnv* env); - -extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { - JNIEnv *env; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { - __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); - return JNI_ERR; - } - - if (register_android_net_TrafficStats(env) < 0) return JNI_ERR; - - return JNI_VERSION_1_6; -} - -}; // namespace android - diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java deleted file mode 100644 index 2b6570a6ecb08..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java +++ /dev/null @@ -1,742 +0,0 @@ -/** - * Copyright (C) 2015 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.app.usage; - -import android.annotation.IntDef; -import android.content.Context; -import android.net.INetworkStatsService; -import android.net.INetworkStatsSession; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.TrafficStats; -import android.os.RemoteException; -import android.util.Log; - -import com.android.net.module.util.CollectionUtils; - -import dalvik.system.CloseGuard; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; - -/** - * Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects - * are returned as results to various queries in {@link NetworkStatsManager}. - */ -public final class NetworkStats implements AutoCloseable { - private final static String TAG = "NetworkStats"; - - private final CloseGuard mCloseGuard = CloseGuard.get(); - - /** - * Start timestamp of stats collected - */ - private final long mStartTimeStamp; - - /** - * End timestamp of stats collected - */ - private final long mEndTimeStamp; - - /** - * Non-null array indicates the query enumerates over uids. - */ - private int[] mUids; - - /** - * Index of the current uid in mUids when doing uid enumeration or a single uid value, - * depending on query type. - */ - private int mUidOrUidIndex; - - /** - * Tag id in case if was specified in the query. - */ - private int mTag = android.net.NetworkStats.TAG_NONE; - - /** - * State in case it was not specified in the query. - */ - private int mState = Bucket.STATE_ALL; - - /** - * The session while the query requires it, null if all the stats have been collected or close() - * has been called. - */ - private INetworkStatsSession mSession; - private NetworkTemplate mTemplate; - - /** - * Results of a summary query. - */ - private android.net.NetworkStats mSummary = null; - - /** - * Results of detail queries. - */ - private NetworkStatsHistory mHistory = null; - - /** - * Where we are in enumerating over the current result. - */ - private int mEnumerationIndex = 0; - - /** - * Recycling entry objects to prevent heap fragmentation. - */ - private android.net.NetworkStats.Entry mRecycledSummaryEntry = null; - private NetworkStatsHistory.Entry mRecycledHistoryEntry = null; - - /** @hide */ - NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp, - long endTimestamp, INetworkStatsService statsService) - throws RemoteException, SecurityException { - // Open network stats session - mSession = statsService.openSessionForUsageStats(flags, context.getOpPackageName()); - mCloseGuard.open("close"); - mTemplate = template; - mStartTimeStamp = startTimestamp; - mEndTimeStamp = endTimestamp; - } - - @Override - protected void finalize() throws Throwable { - try { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } finally { - super.finalize(); - } - } - - // -------------------------BEGINNING OF PUBLIC API----------------------------------- - - /** - * Buckets are the smallest elements of a query result. As some dimensions of a result may be - * aggregated (e.g. time or state) some values may be equal across all buckets. - */ - public static class Bucket { - /** @hide */ - @IntDef(prefix = { "STATE_" }, value = { - STATE_ALL, - STATE_DEFAULT, - STATE_FOREGROUND - }) - @Retention(RetentionPolicy.SOURCE) - public @interface State {} - - /** - * Combined usage across all states. - */ - public static final int STATE_ALL = -1; - - /** - * Usage not accounted for in any other state. - */ - public static final int STATE_DEFAULT = 0x1; - - /** - * Foreground usage. - */ - public static final int STATE_FOREGROUND = 0x2; - - /** - * Special UID value for aggregate/unspecified. - */ - public static final int UID_ALL = android.net.NetworkStats.UID_ALL; - - /** - * Special UID value for removed apps. - */ - public static final int UID_REMOVED = TrafficStats.UID_REMOVED; - - /** - * Special UID value for data usage by tethering. - */ - public static final int UID_TETHERING = TrafficStats.UID_TETHERING; - - /** @hide */ - @IntDef(prefix = { "METERED_" }, value = { - METERED_ALL, - METERED_NO, - METERED_YES - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Metered {} - - /** - * Combined usage across all metered states. Covers metered and unmetered usage. - */ - public static final int METERED_ALL = -1; - - /** - * Usage that occurs on an unmetered network. - */ - public static final int METERED_NO = 0x1; - - /** - * Usage that occurs on a metered network. - * - *

A network is classified as metered when the user is sensitive to heavy data usage on - * that connection. - */ - public static final int METERED_YES = 0x2; - - /** @hide */ - @IntDef(prefix = { "ROAMING_" }, value = { - ROAMING_ALL, - ROAMING_NO, - ROAMING_YES - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Roaming {} - - /** - * Combined usage across all roaming states. Covers both roaming and non-roaming usage. - */ - public static final int ROAMING_ALL = -1; - - /** - * Usage that occurs on a home, non-roaming network. - * - *

Any cellular usage in this bucket was incurred while the device was connected to a - * tower owned or operated by the user's wireless carrier, or a tower that the user's - * wireless carrier has indicated should be treated as a home network regardless. - * - *

This is also the default value for network types that do not support roaming. - */ - public static final int ROAMING_NO = 0x1; - - /** - * Usage that occurs on a roaming network. - * - *

Any cellular usage in this bucket as incurred while the device was roaming on another - * carrier's network, for which additional charges may apply. - */ - public static final int ROAMING_YES = 0x2; - - /** @hide */ - @IntDef(prefix = { "DEFAULT_NETWORK_" }, value = { - DEFAULT_NETWORK_ALL, - DEFAULT_NETWORK_NO, - DEFAULT_NETWORK_YES - }) - @Retention(RetentionPolicy.SOURCE) - public @interface DefaultNetworkStatus {} - - /** - * Combined usage for this network regardless of default network status. - */ - public static final int DEFAULT_NETWORK_ALL = -1; - - /** - * Usage that occurs while this network is not a default network. - * - *

This implies that the app responsible for this usage requested that it occur on a - * specific network different from the one(s) the system would have selected for it. - */ - public static final int DEFAULT_NETWORK_NO = 0x1; - - /** - * Usage that occurs while this network is a default network. - * - *

This implies that the app either did not select a specific network for this usage, - * or it selected a network that the system could have selected for app traffic. - */ - public static final int DEFAULT_NETWORK_YES = 0x2; - - /** - * Special TAG value for total data across all tags - */ - public static final int TAG_NONE = android.net.NetworkStats.TAG_NONE; - - private int mUid; - private int mTag; - private int mState; - private int mDefaultNetworkStatus; - private int mMetered; - private int mRoaming; - private long mBeginTimeStamp; - private long mEndTimeStamp; - private long mRxBytes; - private long mRxPackets; - private long mTxBytes; - private long mTxPackets; - - private static int convertSet(@State int state) { - switch (state) { - case STATE_ALL: return android.net.NetworkStats.SET_ALL; - case STATE_DEFAULT: return android.net.NetworkStats.SET_DEFAULT; - case STATE_FOREGROUND: return android.net.NetworkStats.SET_FOREGROUND; - } - return 0; - } - - private static @State int convertState(int networkStatsSet) { - switch (networkStatsSet) { - case android.net.NetworkStats.SET_ALL : return STATE_ALL; - case android.net.NetworkStats.SET_DEFAULT : return STATE_DEFAULT; - case android.net.NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND; - } - return 0; - } - - private static int convertUid(int uid) { - switch (uid) { - case TrafficStats.UID_REMOVED: return UID_REMOVED; - case TrafficStats.UID_TETHERING: return UID_TETHERING; - } - return uid; - } - - private static int convertTag(int tag) { - switch (tag) { - case android.net.NetworkStats.TAG_NONE: return TAG_NONE; - } - return tag; - } - - private static @Metered int convertMetered(int metered) { - switch (metered) { - case android.net.NetworkStats.METERED_ALL : return METERED_ALL; - case android.net.NetworkStats.METERED_NO: return METERED_NO; - case android.net.NetworkStats.METERED_YES: return METERED_YES; - } - return 0; - } - - private static @Roaming int convertRoaming(int roaming) { - switch (roaming) { - case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; - case android.net.NetworkStats.ROAMING_NO: return ROAMING_NO; - case android.net.NetworkStats.ROAMING_YES: return ROAMING_YES; - } - return 0; - } - - private static @DefaultNetworkStatus int convertDefaultNetworkStatus( - int defaultNetworkStatus) { - switch (defaultNetworkStatus) { - case android.net.NetworkStats.DEFAULT_NETWORK_ALL : return DEFAULT_NETWORK_ALL; - case android.net.NetworkStats.DEFAULT_NETWORK_NO: return DEFAULT_NETWORK_NO; - case android.net.NetworkStats.DEFAULT_NETWORK_YES: return DEFAULT_NETWORK_YES; - } - return 0; - } - - public Bucket() { - } - - /** - * Key of the bucket. Usually an app uid or one of the following special values:

- *

    - *
  • {@link #UID_REMOVED}
  • - *
  • {@link #UID_TETHERING}
  • - *
  • {@link android.os.Process#SYSTEM_UID}
  • - *
- * @return Bucket key. - */ - public int getUid() { - return mUid; - } - - /** - * Tag of the bucket.

- * @return Bucket tag. - */ - public int getTag() { - return mTag; - } - - /** - * Usage state. One of the following values:

- *

    - *
  • {@link #STATE_ALL}
  • - *
  • {@link #STATE_DEFAULT}
  • - *
  • {@link #STATE_FOREGROUND}
  • - *
- * @return Usage state. - */ - public @State int getState() { - return mState; - } - - /** - * Metered state. One of the following values:

- *

    - *
  • {@link #METERED_ALL}
  • - *
  • {@link #METERED_NO}
  • - *
  • {@link #METERED_YES}
  • - *
- *

A network is classified as metered when the user is sensitive to heavy data usage on - * that connection. Apps may warn before using these networks for large downloads. The - * metered state can be set by the user within data usage network restrictions. - */ - public @Metered int getMetered() { - return mMetered; - } - - /** - * Roaming state. One of the following values:

- *

    - *
  • {@link #ROAMING_ALL}
  • - *
  • {@link #ROAMING_NO}
  • - *
  • {@link #ROAMING_YES}
  • - *
- */ - public @Roaming int getRoaming() { - return mRoaming; - } - - /** - * Default network status. One of the following values:

- *

    - *
  • {@link #DEFAULT_NETWORK_ALL}
  • - *
  • {@link #DEFAULT_NETWORK_NO}
  • - *
  • {@link #DEFAULT_NETWORK_YES}
  • - *
- */ - public @DefaultNetworkStatus int getDefaultNetworkStatus() { - return mDefaultNetworkStatus; - } - - /** - * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return Start of interval. - */ - public long getStartTimeStamp() { - return mBeginTimeStamp; - } - - /** - * End timestamp of the bucket's time interval. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return End of interval. - */ - public long getEndTimeStamp() { - return mEndTimeStamp; - } - - /** - * Number of bytes received during the bucket's time interval. Statistics are measured at - * the network layer, so they include both TCP and UDP usage. - * @return Number of bytes. - */ - public long getRxBytes() { - return mRxBytes; - } - - /** - * Number of bytes transmitted during the bucket's time interval. Statistics are measured at - * the network layer, so they include both TCP and UDP usage. - * @return Number of bytes. - */ - public long getTxBytes() { - return mTxBytes; - } - - /** - * Number of packets received during the bucket's time interval. Statistics are measured at - * the network layer, so they include both TCP and UDP usage. - * @return Number of packets. - */ - public long getRxPackets() { - return mRxPackets; - } - - /** - * Number of packets transmitted during the bucket's time interval. Statistics are measured - * at the network layer, so they include both TCP and UDP usage. - * @return Number of packets. - */ - public long getTxPackets() { - return mTxPackets; - } - } - - /** - * Fills the recycled bucket with data of the next bin in the enumeration. - * @param bucketOut Bucket to be filled with data. - * @return true if successfully filled the bucket, false otherwise. - */ - public boolean getNextBucket(Bucket bucketOut) { - if (mSummary != null) { - return getNextSummaryBucket(bucketOut); - } else { - return getNextHistoryBucket(bucketOut); - } - } - - /** - * Check if it is possible to ask for a next bucket in the enumeration. - * @return true if there is at least one more bucket. - */ - public boolean hasNextBucket() { - if (mSummary != null) { - return mEnumerationIndex < mSummary.size(); - } else if (mHistory != null) { - return mEnumerationIndex < mHistory.size() - || hasNextUid(); - } - return false; - } - - /** - * Closes the enumeration. Call this method before this object gets out of scope. - */ - @Override - public void close() { - if (mSession != null) { - try { - mSession.close(); - } catch (RemoteException e) { - Log.w(TAG, e); - // Otherwise, meh - } - } - mSession = null; - if (mCloseGuard != null) { - mCloseGuard.close(); - } - } - - // -------------------------END OF PUBLIC API----------------------------------- - - /** - * Collects device summary results into a Bucket. - * @throws RemoteException - */ - Bucket getDeviceSummaryForNetwork() throws RemoteException { - mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, mStartTimeStamp, mEndTimeStamp); - - // Setting enumeration index beyond end to avoid accidental enumeration over data that does - // not belong to the calling user. - mEnumerationIndex = mSummary.size(); - - return getSummaryAggregate(); - } - - /** - * Collects summary results and sets summary enumeration mode. - * @throws RemoteException - */ - void startSummaryEnumeration() throws RemoteException { - mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp, - false /* includeTags */); - mEnumerationIndex = 0; - } - - /** - * Collects tagged summary results and sets summary enumeration mode. - * @throws RemoteException - */ - void startTaggedSummaryEnumeration() throws RemoteException { - mSummary = mSession.getTaggedSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp); - mEnumerationIndex = 0; - } - - /** - * Collects history results for uid and resets history enumeration index. - */ - void startHistoryUidEnumeration(int uid, int tag, int state) { - mHistory = null; - try { - mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid, - Bucket.convertSet(state), tag, NetworkStatsHistory.FIELD_ALL, - mStartTimeStamp, mEndTimeStamp); - setSingleUidTagState(uid, tag, state); - } catch (RemoteException e) { - Log.w(TAG, e); - // Leaving mHistory null - } - mEnumerationIndex = 0; - } - - /** - * Collects history results for network and resets history enumeration index. - */ - void startHistoryDeviceEnumeration() { - try { - mHistory = mSession.getHistoryIntervalForNetwork( - mTemplate, NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); - } catch (RemoteException e) { - Log.w(TAG, e); - mHistory = null; - } - mEnumerationIndex = 0; - } - - /** - * Starts uid enumeration for current user. - * @throws RemoteException - */ - void startUserUidEnumeration() throws RemoteException { - // TODO: getRelevantUids should be sensitive to time interval. When that's done, - // the filtering logic below can be removed. - int[] uids = mSession.getRelevantUids(); - // Filtering of uids with empty history. - final ArrayList filteredUids = new ArrayList<>(); - for (int uid : uids) { - try { - NetworkStatsHistory history = mSession.getHistoryIntervalForUid(mTemplate, uid, - android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, - NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); - if (history != null && history.size() > 0) { - filteredUids.add(uid); - } - } catch (RemoteException e) { - Log.w(TAG, "Error while getting history of uid " + uid, e); - } - } - mUids = CollectionUtils.toIntArray(filteredUids); - mUidOrUidIndex = -1; - stepHistory(); - } - - /** - * Steps to next uid in enumeration and collects history for that. - */ - private void stepHistory(){ - if (hasNextUid()) { - stepUid(); - mHistory = null; - try { - mHistory = mSession.getHistoryIntervalForUid(mTemplate, getUid(), - android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, - NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); - } catch (RemoteException e) { - Log.w(TAG, e); - // Leaving mHistory null - } - mEnumerationIndex = 0; - } - } - - private void fillBucketFromSummaryEntry(Bucket bucketOut) { - bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); - bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); - bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - bucketOut.mDefaultNetworkStatus = Bucket.convertDefaultNetworkStatus( - mRecycledSummaryEntry.defaultNetwork); - bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); - bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); - bucketOut.mBeginTimeStamp = mStartTimeStamp; - bucketOut.mEndTimeStamp = mEndTimeStamp; - bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes; - bucketOut.mRxPackets = mRecycledSummaryEntry.rxPackets; - bucketOut.mTxBytes = mRecycledSummaryEntry.txBytes; - bucketOut.mTxPackets = mRecycledSummaryEntry.txPackets; - } - - /** - * Getting the next item in summary enumeration. - * @param bucketOut Next item will be set here. - * @return true if a next item could be set. - */ - private boolean getNextSummaryBucket(Bucket bucketOut) { - if (bucketOut != null && mEnumerationIndex < mSummary.size()) { - mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry); - fillBucketFromSummaryEntry(bucketOut); - return true; - } - return false; - } - - Bucket getSummaryAggregate() { - if (mSummary == null) { - return null; - } - Bucket bucket = new Bucket(); - if (mRecycledSummaryEntry == null) { - mRecycledSummaryEntry = new android.net.NetworkStats.Entry(); - } - mSummary.getTotal(mRecycledSummaryEntry); - fillBucketFromSummaryEntry(bucket); - return bucket; - } - - /** - * Getting the next item in a history enumeration. - * @param bucketOut Next item will be set here. - * @return true if a next item could be set. - */ - private boolean getNextHistoryBucket(Bucket bucketOut) { - if (bucketOut != null && mHistory != null) { - if (mEnumerationIndex < mHistory.size()) { - mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++, - mRecycledHistoryEntry); - bucketOut.mUid = Bucket.convertUid(getUid()); - bucketOut.mTag = Bucket.convertTag(mTag); - bucketOut.mState = mState; - bucketOut.mDefaultNetworkStatus = Bucket.DEFAULT_NETWORK_ALL; - bucketOut.mMetered = Bucket.METERED_ALL; - bucketOut.mRoaming = Bucket.ROAMING_ALL; - bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; - bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + - mRecycledHistoryEntry.bucketDuration; - bucketOut.mRxBytes = mRecycledHistoryEntry.rxBytes; - bucketOut.mRxPackets = mRecycledHistoryEntry.rxPackets; - bucketOut.mTxBytes = mRecycledHistoryEntry.txBytes; - bucketOut.mTxPackets = mRecycledHistoryEntry.txPackets; - return true; - } else if (hasNextUid()) { - stepHistory(); - return getNextHistoryBucket(bucketOut); - } - } - return false; - } - - // ------------------ UID LOGIC------------------------ - - private boolean isUidEnumeration() { - return mUids != null; - } - - private boolean hasNextUid() { - return isUidEnumeration() && (mUidOrUidIndex + 1) < mUids.length; - } - - private int getUid() { - // Check if uid enumeration. - if (isUidEnumeration()) { - if (mUidOrUidIndex < 0 || mUidOrUidIndex >= mUids.length) { - throw new IndexOutOfBoundsException( - "Index=" + mUidOrUidIndex + " mUids.length=" + mUids.length); - } - return mUids[mUidOrUidIndex]; - } - // Single uid mode. - return mUidOrUidIndex; - } - - private void setSingleUidTagState(int uid, int tag, int state) { - mUidOrUidIndex = uid; - mTag = tag; - mState = state; - } - - private void stepUid() { - if (mUids != null) { - ++mUidOrUidIndex; - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java deleted file mode 100644 index bf518b2d5a296..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java +++ /dev/null @@ -1,1181 +0,0 @@ -/** - * Copyright (C) 2015 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.app.usage; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; - -import android.Manifest; -import android.annotation.CallbackExecutor; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.annotation.SystemService; -import android.annotation.WorkerThread; -import android.app.usage.NetworkStats.Bucket; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.DataUsageRequest; -import android.net.INetworkStatsService; -import android.net.Network; -import android.net.NetworkStack; -import android.net.NetworkStateSnapshot; -import android.net.NetworkTemplate; -import android.net.UnderlyingNetworkInfo; -import android.net.netstats.IUsageCallback; -import android.net.netstats.NetworkStatsDataMigrationUtils; -import android.net.netstats.provider.INetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProvider; -import android.os.Build; -import android.os.Handler; -import android.os.RemoteException; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.NetworkIdentityUtils; - -import java.util.List; -import java.util.Objects; -import java.util.concurrent.Executor; - -/** - * Provides access to network usage history and statistics. Usage data is collected in - * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. - *

- * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and - * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain - * data about themselves. See the below note for special cases in which apps can obtain data about - * other applications. - *

- * Summary queries - *

- * {@link #querySummaryForDevice}

- * {@link #querySummaryForUser}

- * {@link #querySummary}

- * These queries aggregate network usage across the whole interval. Therefore there will be only one - * bucket for a particular key, state, metered and roaming combination. In case of the user-wide - * and device-wide summaries a single bucket containing the totalised network usage is returned. - *

- * History queries - *

- * {@link #queryDetailsForUid}

- * {@link #queryDetails}

- * These queries do not aggregate over time but do aggregate over state, metered and roaming. - * Therefore there can be multiple buckets for a particular key. However, all Buckets will have - * {@code state} {@link NetworkStats.Bucket#STATE_ALL}, - * {@code defaultNetwork} {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * {@code metered } {@link NetworkStats.Bucket#METERED_ALL}, - * {@code roaming} {@link NetworkStats.Bucket#ROAMING_ALL}. - *

- * NOTE: Calling {@link #querySummaryForDevice} or accessing stats for apps other than the - * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, - * which is a system-level permission and will not be granted to third-party apps. However, - * declaring the permission implies intention to use the API and the user of the device can grant - * permission through the Settings application. - *

- * Profile owner apps are automatically granted permission to query data on the profile they manage - * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier- - * privileged apps likewise get access to usage data for all users on the device. - *

- * In addition to tethering usage, usage by removed users and apps, and usage by the system - * is also included in the results for callers with one of these higher levels of access. - *

- * NOTE: Prior to API level {@value android.os.Build.VERSION_CODES#N}, all calls to these APIs required - * the above permission, even to access an app's own data usage, and carrier-privileged apps were - * not included. - */ -@SystemService(Context.NETWORK_STATS_SERVICE) -public class NetworkStatsManager { - private static final String TAG = "NetworkStatsManager"; - private static final boolean DBG = false; - - /** @hide */ - public static final int CALLBACK_LIMIT_REACHED = 0; - /** @hide */ - public static final int CALLBACK_RELEASED = 1; - - /** - * Minimum data usage threshold for registering usage callbacks. - * - * Requests registered with a threshold lower than this will only be triggered once this minimum - * is reached. - * @hide - */ - public static final long MIN_THRESHOLD_BYTES = 2 * 1_048_576L; // 2MiB - - private final Context mContext; - private final INetworkStatsService mService; - - /** - * @deprecated Use {@link NetworkStatsDataMigrationUtils#PREFIX_XT} - * instead. - * @hide - */ - @Deprecated - public static final String PREFIX_DEV = "dev"; - - /** @hide */ - public static final int FLAG_POLL_ON_OPEN = 1 << 0; - /** @hide */ - public static final int FLAG_POLL_FORCE = 1 << 1; - /** @hide */ - public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 2; - - /** - * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is - * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along - * with NR state as connected. This is a concept added by NetworkStats on top of the telephony - * constants for backward compatibility of metrics so this should not be overlapped with any of - * the {@code TelephonyManager.NETWORK_TYPE_*} constants. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int NETWORK_TYPE_5G_NSA = -2; - - private int mFlags; - - /** @hide */ - @VisibleForTesting - public NetworkStatsManager(Context context, INetworkStatsService service) { - mContext = context; - mService = service; - setPollOnOpen(true); - setAugmentWithSubscriptionPlan(true); - } - - /** @hide */ - public INetworkStatsService getBinder() { - return mService; - } - - /** - * Set poll on open flag to indicate the poll is needed before service gets statistics - * result. This is default enabled. However, for any non-privileged caller, the poll might - * be omitted in case of rate limiting. - * - * @param pollOnOpen true if poll is needed. - * @hide - */ - // The system will ignore any non-default values for non-privileged - // processes, so processes that don't hold the appropriate permissions - // can make no use of this API. - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void setPollOnOpen(boolean pollOnOpen) { - if (pollOnOpen) { - mFlags |= FLAG_POLL_ON_OPEN; - } else { - mFlags &= ~FLAG_POLL_ON_OPEN; - } - } - - /** - * Set poll force flag to indicate that calling any subsequent query method will force a stats - * poll. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @SystemApi(client = MODULE_LIBRARIES) - public void setPollForce(boolean pollForce) { - if (pollForce) { - mFlags |= FLAG_POLL_FORCE; - } else { - mFlags &= ~FLAG_POLL_FORCE; - } - } - - /** @hide */ - public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) { - if (augmentWithSubscriptionPlan) { - mFlags |= FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; - } else { - mFlags &= ~FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; - } - } - - /** - * Query network usage statistics summaries. - * - * Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and - * roaming. This means the bucket's start and end timestamp will be the same as the - * 'startTime' and 'endTime' arguments. State is going to be - * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, - * tag {@link NetworkStats.Bucket#TAG_NONE}, - * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered {@link NetworkStats.Bucket#METERED_ALL}, - * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param startTime Start of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @return Bucket Summarised data usage. - * - * @hide - */ - @NonNull - @WorkerThread - @SystemApi(client = MODULE_LIBRARIES) - public Bucket querySummaryForDevice(@NonNull NetworkTemplate template, - long startTime, long endTime) { - Objects.requireNonNull(template); - try { - NetworkStats stats = - new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - Bucket bucket = stats.getDeviceSummaryForNetwork(); - stats.close(); - return bucket; - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return null; // To make the compiler happy. - } - - /** - * Query network usage statistics summaries. Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and - * roaming. This means the bucket's start and end timestamp are going to be the same as the - * 'startTime' and 'endTime' parameters. State is going to be - * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, - * tag {@link NetworkStats.Bucket#TAG_NONE}, - * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered {@link NetworkStats.Bucket#METERED_ALL}, - * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - *

Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - *

Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return Bucket object or null if permissions are insufficient or error happened during - * statistics collection. - */ - @WorkerThread - public Bucket querySummaryForDevice(int networkType, String subscriberId, - long startTime, long endTime) throws SecurityException, RemoteException { - NetworkTemplate template; - try { - template = createTemplate(networkType, subscriberId); - } catch (IllegalArgumentException e) { - if (DBG) Log.e(TAG, "Cannot create template", e); - return null; - } - - return querySummaryForDevice(template, startTime, endTime); - } - - /** - * Query network usage statistics summaries. Result is summarised data usage for all uids - * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. - * This means the bucket's start and end timestamp are going to be the same as the 'startTime' - * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, - * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, - * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming - * {@link NetworkStats.Bucket#ROAMING_ALL}. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - *

Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - *

Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return Bucket object or null if permissions are insufficient or error happened during - * statistics collection. - */ - @WorkerThread - public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime, - long endTime) throws SecurityException, RemoteException { - NetworkTemplate template; - try { - template = createTemplate(networkType, subscriberId); - } catch (IllegalArgumentException e) { - if (DBG) Log.e(TAG, "Cannot create template", e); - return null; - } - - NetworkStats stats; - stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - stats.startSummaryEnumeration(); - - stats.close(); - return stats.getSummaryAggregate(); - } - - /** - * Query network usage statistics summaries. Result filtered to include only uids belonging to - * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state, uid, default network, metered, or roaming. This - * means buckets' start and end timestamps are going to be the same as the 'startTime' and - * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to - * be the same. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - *

Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - *

Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return Statistics object or null if permissions are insufficient or error happened during - * statistics collection. - */ - @WorkerThread - public NetworkStats querySummary(int networkType, String subscriberId, long startTime, - long endTime) throws SecurityException, RemoteException { - NetworkTemplate template; - try { - template = createTemplate(networkType, subscriberId); - } catch (IllegalArgumentException e) { - if (DBG) Log.e(TAG, "Cannot create template", e); - return null; - } - - return querySummary(template, startTime, endTime); - } - - /** - * Query network usage statistics summaries. - * - * The results will only include traffic made by UIDs belonging to the calling user profile. - * The results are aggregated over time, so that all buckets will have the same start and - * end timestamps as the passed arguments. Not aggregated over state, uid, default network, - * metered, or roaming. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param startTime Start of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @return Statistics which is described above. - * @hide - */ - @NonNull - @SystemApi(client = MODULE_LIBRARIES) - @WorkerThread - public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime, - long endTime) throws SecurityException { - Objects.requireNonNull(template); - try { - NetworkStats result = - new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startSummaryEnumeration(); - return result; - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return null; // To make the compiler happy. - } - - /** - * Query tagged network usage statistics summaries. - * - * The results will only include tagged traffic made by UIDs belonging to the calling user - * profile. The results are aggregated over time, so that all buckets will have the same - * start and end timestamps as the passed arguments. Not aggregated over state, uid, - * default network, metered, or roaming. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param startTime Start of period, in milliseconds since the Unix epoch, see - * {@link System#currentTimeMillis}. - * @param endTime End of period, in milliseconds since the Unix epoch, see - * {@link System#currentTimeMillis}. - * @return Statistics which is described above. - * @hide - */ - @NonNull - @SystemApi(client = MODULE_LIBRARIES) - @WorkerThread - public NetworkStats queryTaggedSummary(@NonNull NetworkTemplate template, long startTime, - long endTime) throws SecurityException { - Objects.requireNonNull(template); - try { - NetworkStats result = - new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startTaggedSummaryEnumeration(); - return result; - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - return null; // To make the compiler happy. - } - - /** - * Query usage statistics details for networks matching a given {@link NetworkTemplate}. - * - * Result is not aggregated over time. This means buckets' start and - * end timestamps will be between 'startTime' and 'endTime' parameters. - *

Only includes buckets whose entire time period is included between - * startTime and endTime. Doesn't interpolate or return partial buckets. - * Since bucket length is in the order of hours, this - * method cannot be used to measure data usage on a fine grained time scale. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param startTime Start of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @return Statistics which is described above. - * @hide - */ - @NonNull - @SystemApi(client = MODULE_LIBRARIES) - @WorkerThread - public NetworkStats queryDetailsForDevice(@NonNull NetworkTemplate template, - long startTime, long endTime) { - Objects.requireNonNull(template); - try { - final NetworkStats result = - new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startHistoryDeviceEnumeration(); - return result; - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - - return null; // To make the compiler happy. - } - - /** - * Query network usage statistics details for a given uid. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) - */ - @WorkerThread - public NetworkStats queryDetailsForUid(int networkType, String subscriberId, - long startTime, long endTime, int uid) throws SecurityException { - return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, - NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); - } - - /** @hide */ - public NetworkStats queryDetailsForUid(NetworkTemplate template, - long startTime, long endTime, int uid) throws SecurityException { - return queryDetailsForUidTagState(template, startTime, endTime, uid, - NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); - } - - /** - * Query network usage statistics details for a given uid and tag. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) - */ - @WorkerThread - public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, - long startTime, long endTime, int uid, int tag) throws SecurityException { - return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, - tag, NetworkStats.Bucket.STATE_ALL); - } - - /** - * Query network usage statistics details for a given uid, tag, and state. Only usable for uids - * belonging to calling user. Result is not aggregated over time. This means buckets' start and - * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going - * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state - * the same as the 'state' parameter. - * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and - * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. - *

Only includes buckets that atomically occur in the inclusive time range. Doesn't - * interpolate across partial buckets. Since bucket length is in the order of hours, this - * method cannot be used to measure data usage on a fine grained time scale. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - *

Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - *

Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param uid UID of app - * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data - * across all the tags. - * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate - * traffic from all states. - * @return Statistics object or null if an error happened during statistics collection. - * @throws SecurityException if permissions are insufficient to read network statistics. - */ - @WorkerThread - public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId, - long startTime, long endTime, int uid, int tag, int state) throws SecurityException { - NetworkTemplate template; - template = createTemplate(networkType, subscriberId); - - return queryDetailsForUidTagState(template, startTime, endTime, uid, tag, state); - } - - /** - * Query network usage statistics details for a given template, uid, tag, and state. - * - * Only usable for uids belonging to calling user. Result is not aggregated over time. - * This means buckets' start and end timestamps are going to be between 'startTime' and - * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag - * the same as the 'tag' parameter, and the state the same as the 'state' parameter. - * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and - * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. - *

Only includes buckets that atomically occur in the inclusive time range. Doesn't - * interpolate across partial buckets. Since bucket length is in the order of hours, this - * method cannot be used to measure data usage on a fine grained time scale. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param startTime Start of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period, in milliseconds since the Unix epoch, see - * {@link java.lang.System#currentTimeMillis}. - * @param uid UID of app - * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data - * across all the tags. - * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate - * traffic from all states. - * @return Statistics which is described above. - * @hide - */ - @NonNull - @SystemApi(client = MODULE_LIBRARIES) - @WorkerThread - public NetworkStats queryDetailsForUidTagState(@NonNull NetworkTemplate template, - long startTime, long endTime, int uid, int tag, int state) throws SecurityException { - Objects.requireNonNull(template); - try { - final NetworkStats result = new NetworkStats( - mContext, template, mFlags, startTime, endTime, mService); - result.startHistoryUidEnumeration(uid, tag, state); - return result; - } catch (RemoteException e) { - Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag - + " state=" + state, e); - e.rethrowFromSystemServer(); - } - - return null; // To make the compiler happy. - } - - /** - * Query network usage statistics details. Result filtered to include only uids belonging to - * calling user. Result is aggregated over state but not aggregated over time, uid, tag, - * metered, nor roaming. This means buckets' start and end timestamps are going to be between - * 'startTime' and 'endTime' parameters. State is going to be - * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, - * tag {@link NetworkStats.Bucket#TAG_NONE}, - * default network is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, - * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, - * and roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. - *

Only includes buckets that atomically occur in the inclusive time range. Doesn't - * interpolate across partial buckets. Since bucket length is in the order of hours, this - * method cannot be used to measure data usage on a fine grained time scale. - * This may take a long time, and apps should avoid calling this on their main thread. - * - * @param networkType As defined in {@link ConnectivityManager}, e.g. - * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} - * etc. - * @param subscriberId If applicable, the subscriber id of the network interface. - *

Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when querying for the mobile network type to receive usage - * for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - *

Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param startTime Start of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @param endTime End of period. Defined in terms of "Unix time", see - * {@link java.lang.System#currentTimeMillis}. - * @return Statistics object or null if permissions are insufficient or error happened during - * statistics collection. - */ - @WorkerThread - public NetworkStats queryDetails(int networkType, String subscriberId, long startTime, - long endTime) throws SecurityException, RemoteException { - NetworkTemplate template; - try { - template = createTemplate(networkType, subscriberId); - } catch (IllegalArgumentException e) { - if (DBG) Log.e(TAG, "Cannot create template", e); - return null; - } - - NetworkStats result; - result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startUserUidEnumeration(); - return result; - } - - /** - * Query realtime mobile network usage statistics. - * - * Return a snapshot of current UID network statistics, as it applies - * to the mobile radios of the device. The snapshot will include any - * tethering traffic, video calling data usage and count of - * network operations set by {@link TrafficStats#incrementOperationCount} - * made over a mobile radio. - * The snapshot will not include any statistics that cannot be seen by - * the kernel, e.g. statistics reported by {@link NetworkStatsProvider}s. - * - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - @NonNull public android.net.NetworkStats getMobileUidStats() { - try { - return mService.getUidStatsForTransport(TRANSPORT_CELLULAR); - } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when get Mobile uid stats"); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Query realtime Wi-Fi network usage statistics. - * - * Return a snapshot of current UID network statistics, as it applies - * to the Wi-Fi radios of the device. The snapshot will include any - * tethering traffic, video calling data usage and count of - * network operations set by {@link TrafficStats#incrementOperationCount} - * made over a Wi-Fi radio. - * The snapshot will not include any statistics that cannot be seen by - * the kernel, e.g. statistics reported by {@link NetworkStatsProvider}s. - * - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - @NonNull public android.net.NetworkStats getWifiUidStats() { - try { - return mService.getUidStatsForTransport(TRANSPORT_WIFI); - } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when get WiFi uid stats"); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Registers to receive notifications about data usage on specified networks. - * - *

The callbacks will continue to be called as long as the process is alive or - * {@link #unregisterUsageCallback} is called. - * - * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param thresholdBytes Threshold in bytes to be notified on. Provided values lower than 2MiB - * will be clamped for callers except callers with the NETWORK_STACK - * permission. - * @param executor The executor on which callback will be invoked. The provided {@link Executor} - * must run callback sequentially, otherwise the order of callbacks cannot be - * guaranteed. - * @param callback The {@link UsageCallback} that the system will call when data usage - * has exceeded the specified threshold. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}, conditional = true) - public void registerUsageCallback(@NonNull NetworkTemplate template, long thresholdBytes, - @NonNull @CallbackExecutor Executor executor, @NonNull UsageCallback callback) { - Objects.requireNonNull(template, "NetworkTemplate cannot be null"); - Objects.requireNonNull(callback, "UsageCallback cannot be null"); - Objects.requireNonNull(executor, "Executor cannot be null"); - - final DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, - template, thresholdBytes); - try { - final UsageCallbackWrapper callbackWrapper = - new UsageCallbackWrapper(executor, callback); - callback.request = mService.registerUsageCallback( - mContext.getOpPackageName(), request, callbackWrapper); - if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); - - if (callback.request == null) { - Log.e(TAG, "Request from callback is null; should not happen"); - } - } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when registering callback"); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Registers to receive notifications about data usage on specified networks. - * - * @see #registerUsageCallback(int, String, long, UsageCallback, Handler) - */ - public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, - UsageCallback callback) { - registerUsageCallback(networkType, subscriberId, thresholdBytes, callback, - null /* handler */); - } - - /** - * Registers to receive notifications about data usage on specified networks. - * - *

The callbacks will continue to be called as long as the process is live or - * {@link #unregisterUsageCallback} is called. - * - * @param networkType Type of network to monitor. Either - {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}. - * @param subscriberId If applicable, the subscriber id of the network interface. - *

Starting with API level 29, the {@code subscriberId} is guarded by - * additional restrictions. Calling apps that do not meet the new - * requirements to access the {@code subscriberId} can provide a {@code - * null} value when registering for the mobile network type to receive - * notifications for all mobile networks. For additional details see {@link - * TelephonyManager#getSubscriberId()}. - *

Starting with API level 31, calling apps can provide a - * {@code subscriberId} with wifi network type to receive usage for - * wifi networks which is under the given subscription if applicable. - * Otherwise, pass {@code null} when querying all wifi networks. - * @param thresholdBytes Threshold in bytes to be notified on. - * @param callback The {@link UsageCallback} that the system will call when data usage - * has exceeded the specified threshold. - * @param handler to dispatch callback events through, otherwise if {@code null} it uses - * the calling thread. - */ - public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, - UsageCallback callback, @Nullable Handler handler) { - NetworkTemplate template = createTemplate(networkType, subscriberId); - if (DBG) { - Log.d(TAG, "registerUsageCallback called with: {" - + " networkType=" + networkType - + " subscriberId=" + subscriberId - + " thresholdBytes=" + thresholdBytes - + " }"); - } - - final Executor executor = handler == null ? r -> r.run() : r -> handler.post(r); - - registerUsageCallback(template, thresholdBytes, executor, callback); - } - - /** - * Unregisters callbacks on data usage. - * - * @param callback The {@link UsageCallback} used when registering. - */ - public void unregisterUsageCallback(UsageCallback callback) { - if (callback == null || callback.request == null - || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { - throw new IllegalArgumentException("Invalid UsageCallback"); - } - try { - mService.unregisterUsageRequest(callback.request); - } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when unregistering callback"); - throw e.rethrowFromSystemServer(); - } - } - - /** - * Base class for usage callbacks. Should be extended by applications wanting notifications. - */ - public static abstract class UsageCallback { - /** - * Called when data usage has reached the given threshold. - * - * Called by {@code NetworkStatsService} when the registered threshold is reached. - * If a caller implements {@link #onThresholdReached(NetworkTemplate)}, the system - * will not call {@link #onThresholdReached(int, String)}. - * - * @param template The {@link NetworkTemplate} that associated with this callback. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public void onThresholdReached(@NonNull NetworkTemplate template) { - // Backward compatibility for those who didn't override this function. - final int networkType = networkTypeForTemplate(template); - if (networkType != ConnectivityManager.TYPE_NONE) { - final String subscriberId = template.getSubscriberIds().isEmpty() ? null - : template.getSubscriberIds().iterator().next(); - onThresholdReached(networkType, subscriberId); - } - } - - /** - * Called when data usage has reached the given threshold. - */ - public abstract void onThresholdReached(int networkType, String subscriberId); - - /** - * @hide used for internal bookkeeping - */ - private DataUsageRequest request; - - /** - * Get network type from a template if feasible. - * - * @param template the target {@link NetworkTemplate}. - * @return legacy network type, only supports for the types which is already supported in - * {@link #registerUsageCallback(int, String, long, UsageCallback, Handler)}. - * {@link ConnectivityManager#TYPE_NONE} for other types. - */ - private static int networkTypeForTemplate(@NonNull NetworkTemplate template) { - switch (template.getMatchRule()) { - case NetworkTemplate.MATCH_MOBILE: - return ConnectivityManager.TYPE_MOBILE; - case NetworkTemplate.MATCH_WIFI: - return ConnectivityManager.TYPE_WIFI; - default: - return ConnectivityManager.TYPE_NONE; - } - } - } - - /** - * Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics - * to the system. To unregister, invoke {@link #unregisterNetworkStatsProvider}. - * Note that no de-duplication of statistics between providers is performed, so each provider - * must only report network traffic that is not being reported by any other provider. Also note - * that the provider cannot be re-registered after unregistering. - * - * @param tag a human readable identifier of the custom network stats provider. This is only - * used for debugging. - * @param provider the subclass of {@link NetworkStatsProvider} that needs to be - * registered to the system. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STATS_PROVIDER, - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) - @NonNull public void registerNetworkStatsProvider( - @NonNull String tag, - @NonNull NetworkStatsProvider provider) { - try { - if (provider.getProviderCallbackBinder() != null) { - throw new IllegalArgumentException("provider is already registered"); - } - final INetworkStatsProviderCallback cbBinder = - mService.registerNetworkStatsProvider(tag, provider.getProviderBinder()); - provider.setProviderCallbackBinder(cbBinder); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Unregisters an instance of {@link NetworkStatsProvider}. - * - * @param provider the subclass of {@link NetworkStatsProvider} that needs to be - * unregistered to the system. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STATS_PROVIDER, - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) - @NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) { - try { - provider.getProviderCallbackBinderOrThrow().unregister(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - private static NetworkTemplate createTemplate(int networkType, String subscriberId) { - final NetworkTemplate template; - switch (networkType) { - case ConnectivityManager.TYPE_MOBILE: - template = subscriberId == null - ? NetworkTemplate.buildTemplateMobileWildcard() - : NetworkTemplate.buildTemplateMobileAll(subscriberId); - break; - case ConnectivityManager.TYPE_WIFI: - template = TextUtils.isEmpty(subscriberId) - ? NetworkTemplate.buildTemplateWifiWildcard() - : NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL, - subscriberId); - break; - default: - throw new IllegalArgumentException("Cannot create template for network type " - + networkType + ", subscriberId '" - + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + "'."); - } - return template; - } - - /** - * Notify {@code NetworkStatsService} about network status changed. - * - * Notifies NetworkStatsService of network state changes for data usage accounting purposes. - * - * To avoid races that attribute data usage to wrong network, such as new network with - * the same interface after SIM hot-swap, this function will not return until - * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from - * all data sources. - * - * @param defaultNetworks the list of all networks that could be used by network traffic that - * does not explicitly select a network. - * @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for - * each network that is currently connected. - * @param activeIface the active (i.e., connected) default network interface for the calling - * uid. Used to determine on which network future calls to - * {@link android.net.TrafficStats#incrementOperationCount} applies to. - * @param underlyingNetworkInfos the list of underlying network information for all - * currently-connected VPNs. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void notifyNetworkStatus( - @NonNull List defaultNetworks, - @NonNull List networkStateSnapshots, - @Nullable String activeIface, - @NonNull List underlyingNetworkInfos) { - try { - Objects.requireNonNull(defaultNetworks); - Objects.requireNonNull(networkStateSnapshots); - Objects.requireNonNull(underlyingNetworkInfos); - mService.notifyNetworkStatus(defaultNetworks.toArray(new Network[0]), - networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface, - underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0])); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private static class UsageCallbackWrapper extends IUsageCallback.Stub { - // Null if unregistered. - private volatile UsageCallback mCallback; - - private final Executor mExecutor; - - UsageCallbackWrapper(@NonNull Executor executor, @NonNull UsageCallback callback) { - mCallback = callback; - mExecutor = executor; - } - - @Override - public void onThresholdReached(DataUsageRequest request) { - // Copy it to a local variable in case mCallback changed inside the if condition. - final UsageCallback callback = mCallback; - if (callback != null) { - mExecutor.execute(() -> callback.onThresholdReached(request.template)); - } else { - Log.e(TAG, "onThresholdReached with released callback for " + request); - } - } - - @Override - public void onCallbackReleased(DataUsageRequest request) { - if (DBG) Log.d(TAG, "callback released for " + request); - mCallback = null; - } - } - - /** - * Mark given UID as being in foreground for stats purposes. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void noteUidForeground(int uid, boolean uidForeground) { - try { - mService.noteUidForeground(uid, uidForeground); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set default value of global alert bytes, the value will be clamped to [128kB, 2MB]. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - Manifest.permission.NETWORK_STACK}) - public void setDefaultGlobalAlert(long alertBytes) { - try { - // TODO: Sync internal naming with the API surface. - mService.advisePersistThreshold(alertBytes); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Force update of statistics. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void forceUpdate() { - try { - mService.forceUpdate(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set the warning and limit to all registered custom network stats providers. - * Note that invocation of any interface will be sent to all providers. - * - * Asynchronicity notes : because traffic may be happening on the device at the same time, it - * doesn't make sense to wait for the warning and limit to be set – a caller still wouldn't - * know when exactly it was effective. All that can matter is that it's done quickly. Also, - * this method can't fail, so there is no status to return. All providers will see the new - * values soon. - * As such, this method returns immediately and sends the warning and limit to all providers - * as soon as possible through a one-way binder call. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void setStatsProviderWarningAndLimitAsync(@NonNull String iface, long warning, - long limit) { - try { - mService.setStatsProviderWarningAndLimitAsync(iface, warning, limit); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get a RAT type representative of a group of RAT types for network statistics. - * - * Collapse the given Radio Access Technology (RAT) type into a bucket that - * is representative of the original RAT type for network statistics. The - * mapping mostly corresponds to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*} - * but with adaptations specific to the virtual types introduced by - * networks stats. - * - * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static int getCollapsedRatType(int ratType) { - switch (ratType) { - case TelephonyManager.NETWORK_TYPE_GPRS: - case TelephonyManager.NETWORK_TYPE_GSM: - case TelephonyManager.NETWORK_TYPE_EDGE: - case TelephonyManager.NETWORK_TYPE_IDEN: - case TelephonyManager.NETWORK_TYPE_CDMA: - case TelephonyManager.NETWORK_TYPE_1xRTT: - return TelephonyManager.NETWORK_TYPE_GSM; - case TelephonyManager.NETWORK_TYPE_EVDO_0: - case TelephonyManager.NETWORK_TYPE_EVDO_A: - case TelephonyManager.NETWORK_TYPE_EVDO_B: - case TelephonyManager.NETWORK_TYPE_EHRPD: - case TelephonyManager.NETWORK_TYPE_UMTS: - case TelephonyManager.NETWORK_TYPE_HSDPA: - case TelephonyManager.NETWORK_TYPE_HSUPA: - case TelephonyManager.NETWORK_TYPE_HSPA: - case TelephonyManager.NETWORK_TYPE_HSPAP: - case TelephonyManager.NETWORK_TYPE_TD_SCDMA: - return TelephonyManager.NETWORK_TYPE_UMTS; - case TelephonyManager.NETWORK_TYPE_LTE: - case TelephonyManager.NETWORK_TYPE_IWLAN: - return TelephonyManager.NETWORK_TYPE_LTE; - case TelephonyManager.NETWORK_TYPE_NR: - return TelephonyManager.NETWORK_TYPE_NR; - // Virtual RAT type for 5G NSA mode, see - // {@link NetworkStatsManager#NETWORK_TYPE_5G_NSA}. - case NetworkStatsManager.NETWORK_TYPE_5G_NSA: - return NetworkStatsManager.NETWORK_TYPE_5G_NSA; - default: - return TelephonyManager.NETWORK_TYPE_UNKNOWN; - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java deleted file mode 100644 index 61b34d0bcfe66..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import android.annotation.SystemApi; -import android.app.SystemServiceRegistry; -import android.app.usage.NetworkStatsManager; -import android.content.Context; -import android.net.nsd.INsdManager; -import android.net.nsd.NsdManager; - -/** - * Class for performing registration for Connectivity services which are exposed via updatable APIs - * since Android T. - * - * @hide - */ -@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) -public final class ConnectivityFrameworkInitializerTiramisu { - private ConnectivityFrameworkInitializerTiramisu() {} - - /** - * Called by {@link SystemServiceRegistry}'s static initializer and registers NetworkStats, nsd, - * ipsec and ethernet services to {@link Context}, so that {@link Context#getSystemService} can - * return them. - * - * @throws IllegalStateException if this is called anywhere besides - * {@link SystemServiceRegistry}. - */ - public static void registerServiceWrappers() { - SystemServiceRegistry.registerContextAwareService( - Context.NSD_SERVICE, - NsdManager.class, - (context, serviceBinder) -> { - INsdManager service = INsdManager.Stub.asInterface(serviceBinder); - return new NsdManager(context, service); - } - ); - - SystemServiceRegistry.registerContextAwareService( - Context.IPSEC_SERVICE, - IpSecManager.class, - (context, serviceBinder) -> { - IIpSecService service = IIpSecService.Stub.asInterface(serviceBinder); - return new IpSecManager(context, service); - } - ); - - SystemServiceRegistry.registerContextAwareService( - Context.NETWORK_STATS_SERVICE, - NetworkStatsManager.class, - (context, serviceBinder) -> { - INetworkStatsService service = - INetworkStatsService.Stub.asInterface(serviceBinder); - return new NetworkStatsManager(context, service); - } - ); - - SystemServiceRegistry.registerContextAwareService( - Context.ETHERNET_SERVICE, - EthernetManager.class, - (context, serviceBinder) -> { - IEthernetManager service = IEthernetManager.Stub.asInterface(serviceBinder); - return new EthernetManager(context, service); - } - ); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.aidl b/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.aidl deleted file mode 100644 index d1937c7b8c623..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2016, 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; - -parcelable DataUsageRequest; diff --git a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java b/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java deleted file mode 100644 index b06d515b3acff..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/DataUsageRequest.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (C) 2016 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; - -import android.annotation.Nullable; -import android.net.NetworkTemplate; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** - * Defines a request to register a callbacks. Used to be notified on data usage via - * {@link android.app.usage.NetworkStatsManager#registerDataUsageCallback}. - * If no {@code uid}s are set, callbacks are restricted to device-owners, - * carrier-privileged apps, or system apps. - * - * @hide - */ -public final class DataUsageRequest implements Parcelable { - - public static final String PARCELABLE_KEY = "DataUsageRequest"; - public static final int REQUEST_ID_UNSET = 0; - - /** - * Identifies the request. {@link DataUsageRequest}s should only be constructed by - * the Framework and it is used internally to identify the request. - */ - public final int requestId; - - /** - * {@link NetworkTemplate} describing the network to monitor. - */ - public final NetworkTemplate template; - - /** - * Threshold in bytes to be notified on. - */ - public final long thresholdInBytes; - - public DataUsageRequest(int requestId, NetworkTemplate template, long thresholdInBytes) { - this.requestId = requestId; - this.template = template; - this.thresholdInBytes = thresholdInBytes; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(requestId); - dest.writeParcelable(template, flags); - dest.writeLong(thresholdInBytes); - } - - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - @Override - public DataUsageRequest createFromParcel(Parcel in) { - int requestId = in.readInt(); - NetworkTemplate template = in.readParcelable(null); - long thresholdInBytes = in.readLong(); - DataUsageRequest result = new DataUsageRequest(requestId, template, - thresholdInBytes); - return result; - } - - @Override - public DataUsageRequest[] newArray(int size) { - return new DataUsageRequest[size]; - } - }; - - @Override - public String toString() { - return "DataUsageRequest [ requestId=" + requestId - + ", networkTemplate=" + template - + ", thresholdInBytes=" + thresholdInBytes + " ]"; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof DataUsageRequest == false) return false; - DataUsageRequest that = (DataUsageRequest) obj; - return that.requestId == this.requestId - && Objects.equals(that.template, this.template) - && that.thresholdInBytes == this.thresholdInBytes; - } - - @Override - public int hashCode() { - return Objects.hash(requestId, template, thresholdInBytes); - } - -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java deleted file mode 100644 index e02ea897dbe69..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java +++ /dev/null @@ -1,729 +0,0 @@ -/* - * Copyright (C) 2014 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; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import android.annotation.CallbackExecutor; -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresFeature; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.annotation.SystemService; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.OutcomeReceiver; -import android.os.RemoteException; - -import com.android.internal.annotations.GuardedBy; -import com.android.modules.utils.BackgroundThread; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.Executor; -import java.util.function.IntConsumer; - -/** - * A class that manages and configures Ethernet interfaces. - * - * @hide - */ -@SystemApi -@SystemService(Context.ETHERNET_SERVICE) -public class EthernetManager { - private static final String TAG = "EthernetManager"; - - private final IEthernetManager mService; - @GuardedBy("mListenerLock") - private final ArrayList> mIfaceListeners = - new ArrayList<>(); - @GuardedBy("mListenerLock") - private final ArrayList> mEthernetStateListeners = - new ArrayList<>(); - final Object mListenerLock = new Object(); - private final IEthernetServiceListener.Stub mServiceListener = - new IEthernetServiceListener.Stub() { - @Override - public void onEthernetStateChanged(int state) { - synchronized (mListenerLock) { - for (ListenerInfo li : mEthernetStateListeners) { - li.executor.execute(() -> { - li.listener.accept(state); - }); - } - } - } - - @Override - public void onInterfaceStateChanged(String iface, int state, int role, - IpConfiguration configuration) { - synchronized (mListenerLock) { - for (ListenerInfo li : mIfaceListeners) { - li.executor.execute(() -> - li.listener.onInterfaceStateChanged(iface, state, role, - configuration)); - } - } - } - }; - - /** - * Indicates that Ethernet is disabled. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int ETHERNET_STATE_DISABLED = 0; - - /** - * Indicates that Ethernet is enabled. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int ETHERNET_STATE_ENABLED = 1; - - private static class ListenerInfo { - @NonNull - public final Executor executor; - @NonNull - public final T listener; - - private ListenerInfo(@NonNull Executor executor, @NonNull T listener) { - this.executor = executor; - this.listener = listener; - } - } - - /** - * The interface is absent. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int STATE_ABSENT = 0; - - /** - * The interface is present but link is down. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int STATE_LINK_DOWN = 1; - - /** - * The interface is present and link is up. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int STATE_LINK_UP = 2; - - /** @hide */ - @IntDef(prefix = "STATE_", value = {STATE_ABSENT, STATE_LINK_DOWN, STATE_LINK_UP}) - @Retention(RetentionPolicy.SOURCE) - public @interface InterfaceState {} - - /** - * The interface currently does not have any specific role. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int ROLE_NONE = 0; - - /** - * The interface is in client mode (e.g., connected to the Internet). - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int ROLE_CLIENT = 1; - - /** - * Ethernet interface is in server mode (e.g., providing Internet access to tethered devices). - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int ROLE_SERVER = 2; - - /** @hide */ - @IntDef(prefix = "ROLE_", value = {ROLE_NONE, ROLE_CLIENT, ROLE_SERVER}) - @Retention(RetentionPolicy.SOURCE) - public @interface Role {} - - /** - * A listener that receives notifications about the state of Ethernet interfaces on the system. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public interface InterfaceStateListener { - /** - * Called when an Ethernet interface changes state. - * - * @param iface the name of the interface. - * @param state the current state of the interface, or {@link #STATE_ABSENT} if the - * interface was removed. - * @param role whether the interface is in client mode or server mode. - * @param configuration the current IP configuration of the interface. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state, - @Role int role, @Nullable IpConfiguration configuration); - } - - /** - * A listener interface to receive notification on changes in Ethernet. - * This has never been a supported API. Use {@link InterfaceStateListener} instead. - * @hide - */ - public interface Listener extends InterfaceStateListener { - /** - * Called when Ethernet port's availability is changed. - * @param iface Ethernet interface name - * @param isAvailable {@code true} if Ethernet port exists. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - void onAvailabilityChanged(String iface, boolean isAvailable); - - /** Default implementation for backwards compatibility. Only calls the legacy listener. */ - default void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state, - @Role int role, @Nullable IpConfiguration configuration) { - onAvailabilityChanged(iface, (state >= STATE_LINK_UP)); - } - - } - - /** - * Create a new EthernetManager instance. - * Applications will almost always want to use - * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve - * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}. - * @hide - */ - public EthernetManager(Context context, IEthernetManager service) { - mService = service; - } - - /** - * Get Ethernet configuration. - * @return the Ethernet Configuration, contained in {@link IpConfiguration}. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public IpConfiguration getConfiguration(String iface) { - try { - return mService.getConfiguration(iface); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set Ethernet configuration. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void setConfiguration(@NonNull String iface, @NonNull IpConfiguration config) { - try { - mService.setConfiguration(iface, config); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Indicates whether the system currently has one or more Ethernet interfaces. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean isAvailable() { - return getAvailableInterfaces().length > 0; - } - - /** - * Indicates whether the system has given interface. - * - * @param iface Ethernet interface name - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean isAvailable(String iface) { - try { - return mService.isAvailable(iface); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Adds a listener. - * This has never been a supported API. Use {@link #addInterfaceStateListener} instead. - * - * @param listener A {@link Listener} to add. - * @throws IllegalArgumentException If the listener is null. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void addListener(@NonNull Listener listener) { - addListener(listener, BackgroundThread.getExecutor()); - } - - /** - * Adds a listener. - * This has never been a supported API. Use {@link #addInterfaceStateListener} instead. - * - * @param listener A {@link Listener} to add. - * @param executor Executor to run callbacks on. - * @throws IllegalArgumentException If the listener or executor is null. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void addListener(@NonNull Listener listener, @NonNull Executor executor) { - addInterfaceStateListener(executor, listener); - } - - /** - * Listen to changes in the state of Ethernet interfaces. - * - * Adds a listener to receive notification for any state change of all existing Ethernet - * interfaces. - *

{@link Listener#onInterfaceStateChanged} will be triggered immediately for all - * existing interfaces upon adding a listener. The same method will be called on the - * listener every time any of the interface changes state. In particular, if an - * interface is removed, it will be called with state {@link #STATE_ABSENT}. - *

Use {@link #removeInterfaceStateListener} with the same object to stop listening. - * - * @param executor Executor to run callbacks on. - * @param listener A {@link Listener} to add. - * @hide - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @SystemApi(client = MODULE_LIBRARIES) - public void addInterfaceStateListener(@NonNull Executor executor, - @NonNull InterfaceStateListener listener) { - if (listener == null || executor == null) { - throw new NullPointerException("listener and executor must not be null"); - } - synchronized (mListenerLock) { - maybeAddServiceListener(); - mIfaceListeners.add(new ListenerInfo(executor, listener)); - } - } - - @GuardedBy("mListenerLock") - private void maybeAddServiceListener() { - if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return; - - try { - mService.addListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - - } - - /** - * Returns an array of available Ethernet interface names. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public String[] getAvailableInterfaces() { - try { - return mService.getAvailableInterfaces(); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } - - /** - * Removes a listener. - * - * @param listener A {@link Listener} to remove. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) { - Objects.requireNonNull(listener); - synchronized (mListenerLock) { - mIfaceListeners.removeIf(l -> l.listener == listener); - maybeRemoveServiceListener(); - } - } - - @GuardedBy("mListenerLock") - private void maybeRemoveServiceListener() { - if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return; - - try { - mService.removeListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Removes a listener. - * This has never been a supported API. Use {@link #removeInterfaceStateListener} instead. - * @param listener A {@link Listener} to remove. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void removeListener(@NonNull Listener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - removeInterfaceStateListener(listener); - } - - /** - * Whether to treat interfaces created by {@link TestNetworkManager#createTapInterface} - * as Ethernet interfaces. The effects of this method apply to any test interfaces that are - * already present on the system. - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public void setIncludeTestInterfaces(boolean include) { - try { - mService.setIncludeTestInterfaces(include); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * A request for a tethered interface. - */ - public static class TetheredInterfaceRequest { - private final IEthernetManager mService; - private final ITetheredInterfaceCallback mCb; - - private TetheredInterfaceRequest(@NonNull IEthernetManager service, - @NonNull ITetheredInterfaceCallback cb) { - this.mService = service; - this.mCb = cb; - } - - /** - * Release the request, causing the interface to revert back from tethering mode if there - * is no other requestor. - */ - public void release() { - try { - mService.releaseTetheredInterface(mCb); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - } - - /** - * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}. - */ - public interface TetheredInterfaceCallback { - /** - * Called when the tethered interface is available. - * @param iface The name of the interface. - */ - void onAvailable(@NonNull String iface); - - /** - * Called when the tethered interface is now unavailable. - */ - void onUnavailable(); - } - - /** - * Request a tethered interface in tethering mode. - * - *

When this method is called and there is at least one ethernet interface available, the - * system will designate one to act as a tethered interface. If there is already a tethered - * interface, the existing interface will be used. - * @param callback A callback to be called once the request has been fulfilled. - */ - @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STACK, - android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK - }) - @NonNull - public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor, - @NonNull final TetheredInterfaceCallback callback) { - Objects.requireNonNull(callback, "Callback must be non-null"); - Objects.requireNonNull(executor, "Executor must be non-null"); - final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() { - @Override - public void onAvailable(String iface) { - executor.execute(() -> callback.onAvailable(iface)); - } - - @Override - public void onUnavailable() { - executor.execute(() -> callback.onUnavailable()); - } - }; - - try { - mService.requestTetheredInterface(cbInternal); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return new TetheredInterfaceRequest(mService, cbInternal); - } - - private static final class NetworkInterfaceOutcomeReceiver - extends INetworkInterfaceOutcomeReceiver.Stub { - @NonNull - private final Executor mExecutor; - @NonNull - private final OutcomeReceiver mCallback; - - NetworkInterfaceOutcomeReceiver( - @NonNull final Executor executor, - @NonNull final OutcomeReceiver - callback) { - Objects.requireNonNull(executor, "Pass a non-null executor"); - Objects.requireNonNull(callback, "Pass a non-null callback"); - mExecutor = executor; - mCallback = callback; - } - - @Override - public void onResult(@NonNull String iface) { - mExecutor.execute(() -> mCallback.onResult(iface)); - } - - @Override - public void onError(@NonNull EthernetNetworkManagementException e) { - mExecutor.execute(() -> mCallback.onError(e)); - } - } - - private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver( - @Nullable final Executor executor, - @Nullable final OutcomeReceiver callback) { - if (null != callback) { - Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback"); - } - final NetworkInterfaceOutcomeReceiver proxy; - if (null == callback) { - proxy = null; - } else { - proxy = new NetworkInterfaceOutcomeReceiver(executor, callback); - } - return proxy; - } - - /** - * Updates the configuration of an automotive device's ethernet network. - * - * The {@link EthernetNetworkUpdateRequest} {@code request} argument describes how to update the - * configuration for this network. - * Use {@link StaticIpConfiguration.Builder} to build a {@code StaticIpConfiguration} object for - * this network to put inside the {@code request}. - * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities} - * object for this network to put inside the {@code request}. - * - * This function accepts an {@link OutcomeReceiver} that is called once the operation has - * finished execution. - * - * @param iface the name of the interface to act upon. - * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's - * {@link StaticIpConfiguration} and {@link NetworkCapabilities} values. - * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. - * @param callback an optional {@link OutcomeReceiver} to listen for completion of the - * operation. On success, {@link OutcomeReceiver#onResult} is called with the - * interface name. On error, {@link OutcomeReceiver#onError} is called with more - * information about the error. - * @throws SecurityException if the process doesn't hold - * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @throws UnsupportedOperationException if called on a non-automotive device or on an - * unsupported interface. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK, - android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) - public void updateConfiguration( - @NonNull String iface, - @NonNull EthernetNetworkUpdateRequest request, - @Nullable @CallbackExecutor Executor executor, - @Nullable OutcomeReceiver callback) { - Objects.requireNonNull(iface, "iface must be non-null"); - Objects.requireNonNull(request, "request must be non-null"); - final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( - executor, callback); - try { - mService.updateConfiguration(iface, request, proxy); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Enable a network interface. - * - * Enables a previously disabled network interface. - * This function accepts an {@link OutcomeReceiver} that is called once the operation has - * finished execution. - * - * @param iface the name of the interface to enable. - * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. - * @param callback an optional {@link OutcomeReceiver} to listen for completion of the - * operation. On success, {@link OutcomeReceiver#onResult} is called with the - * interface name. On error, {@link OutcomeReceiver#onError} is called with more - * information about the error. - * @throws SecurityException if the process doesn't hold - * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK, - android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) - @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) - public void enableInterface( - @NonNull String iface, - @Nullable @CallbackExecutor Executor executor, - @Nullable OutcomeReceiver callback) { - Objects.requireNonNull(iface, "iface must be non-null"); - final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( - executor, callback); - try { - mService.connectNetwork(iface, proxy); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Disable a network interface. - * - * Disables the use of a network interface to fulfill network requests. If the interface - * currently serves a request, the network will be torn down. - * This function accepts an {@link OutcomeReceiver} that is called once the operation has - * finished execution. - * - * @param iface the name of the interface to disable. - * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. - * @param callback an optional {@link OutcomeReceiver} to listen for completion of the - * operation. On success, {@link OutcomeReceiver#onResult} is called with the - * interface name. On error, {@link OutcomeReceiver#onError} is called with more - * information about the error. - * @throws SecurityException if the process doesn't hold - * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @hide - */ - @SystemApi - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK, - android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) - @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) - public void disableInterface( - @NonNull String iface, - @Nullable @CallbackExecutor Executor executor, - @Nullable OutcomeReceiver callback) { - Objects.requireNonNull(iface, "iface must be non-null"); - final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( - executor, callback); - try { - mService.disconnectNetwork(iface, proxy); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Change ethernet setting. - * - * @param enabled enable or disable ethernet settings. - * - * @hide - */ - @RequiresPermission(anyOf = { - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK, - android.Manifest.permission.NETWORK_SETTINGS}) - @SystemApi(client = MODULE_LIBRARIES) - public void setEthernetEnabled(boolean enabled) { - try { - mService.setEthernetEnabled(enabled); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Listen to changes in the state of ethernet. - * - * @param executor to run callbacks on. - * @param listener to listen ethernet state changed. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @SystemApi(client = MODULE_LIBRARIES) - public void addEthernetStateListener(@NonNull Executor executor, - @NonNull IntConsumer listener) { - Objects.requireNonNull(executor); - Objects.requireNonNull(listener); - synchronized (mListenerLock) { - maybeAddServiceListener(); - mEthernetStateListeners.add(new ListenerInfo(executor, listener)); - } - } - - /** - * Removes a listener. - * - * @param listener to listen ethernet state changed. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @SystemApi(client = MODULE_LIBRARIES) - public void removeEthernetStateListener(@NonNull IntConsumer listener) { - Objects.requireNonNull(listener); - synchronized (mListenerLock) { - mEthernetStateListeners.removeIf(l -> l.listener == listener); - maybeRemoveServiceListener(); - } - } - - /** - * Returns an array of existing Ethernet interface names regardless whether the interface - * is available or not currently. - * @hide - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @SystemApi(client = MODULE_LIBRARIES) - @NonNull - public List getInterfaceList() { - try { - return mService.getInterfaceList(); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl deleted file mode 100644 index adf9e5a4db9db..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2021 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; - - parcelable EthernetNetworkManagementException; \ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java deleted file mode 100644 index a69cc55363b26..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkManagementException.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** @hide */ -@SystemApi -public final class EthernetNetworkManagementException - extends RuntimeException implements Parcelable { - - /* @hide */ - public EthernetNetworkManagementException(@NonNull final String errorMessage) { - super(errorMessage); - } - - @Override - public int hashCode() { - return Objects.hash(getMessage()); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - final EthernetNetworkManagementException that = (EthernetNetworkManagementException) obj; - - return Objects.equals(getMessage(), that.getMessage()); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(getMessage()); - } - - @Override - public int describeContents() { - return 0; - } - - @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public EthernetNetworkManagementException[] newArray(int size) { - return new EthernetNetworkManagementException[size]; - } - - @Override - public EthernetNetworkManagementException createFromParcel(@NonNull Parcel source) { - return new EthernetNetworkManagementException(source.readString()); - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java deleted file mode 100644 index e4d6e248d48a3..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkSpecifier.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; - -import java.util.Objects; - -/** - * A {@link NetworkSpecifier} used to identify ethernet interfaces. - * - * @see EthernetManager - */ -public final class EthernetNetworkSpecifier extends NetworkSpecifier implements Parcelable { - - /** - * Name of the network interface. - */ - @NonNull - private final String mInterfaceName; - - /** - * Create a new EthernetNetworkSpecifier. - * @param interfaceName Name of the ethernet interface the specifier refers to. - */ - public EthernetNetworkSpecifier(@NonNull String interfaceName) { - if (TextUtils.isEmpty(interfaceName)) { - throw new IllegalArgumentException(); - } - mInterfaceName = interfaceName; - } - - /** - * Get the name of the ethernet interface the specifier refers to. - */ - @Nullable - public String getInterfaceName() { - // This may be null in the future to support specifiers based on data other than the - // interface name. - return mInterfaceName; - } - - /** @hide */ - @Override - public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) { - return equals(other); - } - - @Override - public boolean equals(@Nullable Object o) { - if (!(o instanceof EthernetNetworkSpecifier)) return false; - return TextUtils.equals(mInterfaceName, ((EthernetNetworkSpecifier) o).mInterfaceName); - } - - @Override - public int hashCode() { - return Objects.hashCode(mInterfaceName); - } - - @Override - public String toString() { - return "EthernetNetworkSpecifier (" + mInterfaceName + ")"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(mInterfaceName); - } - - public static final @NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public EthernetNetworkSpecifier createFromParcel(Parcel in) { - return new EthernetNetworkSpecifier(in.readString()); - } - public EthernetNetworkSpecifier[] newArray(int size) { - return new EthernetNetworkSpecifier[size]; - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl deleted file mode 100644 index debc348ea3637..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2021 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; - - parcelable EthernetNetworkUpdateRequest; \ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java deleted file mode 100644 index 1691942c3675c..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.Objects; - -/** - * Represents a request to update an existing Ethernet interface. - * - * @see EthernetManager#updateConfiguration - * - * @hide - */ -@SystemApi -public final class EthernetNetworkUpdateRequest implements Parcelable { - @Nullable - private final IpConfiguration mIpConfig; - @Nullable - private final NetworkCapabilities mNetworkCapabilities; - - /** - * Setting the {@link IpConfiguration} is optional in {@link EthernetNetworkUpdateRequest}. - * When set to null, the existing IpConfiguration is not updated. - * - * @return the new {@link IpConfiguration} or null. - */ - @Nullable - public IpConfiguration getIpConfiguration() { - return mIpConfig == null ? null : new IpConfiguration(mIpConfig); - } - - /** - * Setting the {@link NetworkCapabilities} is optional in {@link EthernetNetworkUpdateRequest}. - * When set to null, the existing NetworkCapabilities are not updated. - * - * @return the new {@link NetworkCapabilities} or null. - */ - @Nullable - public NetworkCapabilities getNetworkCapabilities() { - return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities); - } - - private EthernetNetworkUpdateRequest(@Nullable final IpConfiguration ipConfig, - @Nullable final NetworkCapabilities networkCapabilities) { - mIpConfig = ipConfig; - mNetworkCapabilities = networkCapabilities; - } - - private EthernetNetworkUpdateRequest(@NonNull final Parcel source) { - Objects.requireNonNull(source); - mIpConfig = source.readParcelable(IpConfiguration.class.getClassLoader(), - IpConfiguration.class); - mNetworkCapabilities = source.readParcelable(NetworkCapabilities.class.getClassLoader(), - NetworkCapabilities.class); - } - - /** - * Builder used to create {@link EthernetNetworkUpdateRequest} objects. - */ - public static final class Builder { - @Nullable - private IpConfiguration mBuilderIpConfig; - @Nullable - private NetworkCapabilities mBuilderNetworkCapabilities; - - public Builder(){} - - /** - * Constructor to populate the builder's values with an already built - * {@link EthernetNetworkUpdateRequest}. - * @param request the {@link EthernetNetworkUpdateRequest} to populate with. - */ - public Builder(@NonNull final EthernetNetworkUpdateRequest request) { - Objects.requireNonNull(request); - mBuilderIpConfig = null == request.mIpConfig - ? null : new IpConfiguration(request.mIpConfig); - mBuilderNetworkCapabilities = null == request.mNetworkCapabilities - ? null : new NetworkCapabilities(request.mNetworkCapabilities); - } - - /** - * Set the {@link IpConfiguration} to be used with the {@code Builder}. - * @param ipConfig the {@link IpConfiguration} to set. - * @return The builder to facilitate chaining. - */ - @NonNull - public Builder setIpConfiguration(@Nullable final IpConfiguration ipConfig) { - mBuilderIpConfig = ipConfig == null ? null : new IpConfiguration(ipConfig); - return this; - } - - /** - * Set the {@link NetworkCapabilities} to be used with the {@code Builder}. - * @param nc the {@link NetworkCapabilities} to set. - * @return The builder to facilitate chaining. - */ - @NonNull - public Builder setNetworkCapabilities(@Nullable final NetworkCapabilities nc) { - mBuilderNetworkCapabilities = nc == null ? null : new NetworkCapabilities(nc); - return this; - } - - /** - * Build {@link EthernetNetworkUpdateRequest} return the current update request. - * - * @throws IllegalStateException when both mBuilderNetworkCapabilities and mBuilderIpConfig - * are null. - */ - @NonNull - public EthernetNetworkUpdateRequest build() { - if (mBuilderIpConfig == null && mBuilderNetworkCapabilities == null) { - throw new IllegalStateException( - "Cannot construct an empty EthernetNetworkUpdateRequest"); - } - return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities); - } - } - - @Override - public String toString() { - return "EthernetNetworkUpdateRequest{" - + "mIpConfig=" + mIpConfig - + ", mNetworkCapabilities=" + mNetworkCapabilities + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - EthernetNetworkUpdateRequest that = (EthernetNetworkUpdateRequest) o; - - return Objects.equals(that.getIpConfiguration(), mIpConfig) - && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities); - } - - @Override - public int hashCode() { - return Objects.hash(mIpConfig, mNetworkCapabilities); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeParcelable(mIpConfig, flags); - dest.writeParcelable(mNetworkCapabilities, flags); - } - - @Override - public int describeContents() { - return 0; - } - - @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public EthernetNetworkUpdateRequest[] newArray(int size) { - return new EthernetNetworkUpdateRequest[size]; - } - - @Override - public EthernetNetworkUpdateRequest createFromParcel(@NonNull Parcel source) { - return new EthernetNetworkUpdateRequest(source); - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl deleted file mode 100644 index 42e4c1ac55aa3..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetManager.aidl +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2014 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; - -import android.net.IpConfiguration; -import android.net.IEthernetServiceListener; -import android.net.EthernetNetworkManagementException; -import android.net.EthernetNetworkUpdateRequest; -import android.net.INetworkInterfaceOutcomeReceiver; -import android.net.ITetheredInterfaceCallback; - -import java.util.List; - -/** - * Interface that answers queries about, and allows changing - * ethernet configuration. - */ -/** {@hide} */ -interface IEthernetManager -{ - String[] getAvailableInterfaces(); - IpConfiguration getConfiguration(String iface); - void setConfiguration(String iface, in IpConfiguration config); - boolean isAvailable(String iface); - void addListener(in IEthernetServiceListener listener); - void removeListener(in IEthernetServiceListener listener); - void setIncludeTestInterfaces(boolean include); - void requestTetheredInterface(in ITetheredInterfaceCallback callback); - void releaseTetheredInterface(in ITetheredInterfaceCallback callback); - void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request, - in INetworkInterfaceOutcomeReceiver listener); - void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); - void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); - void setEthernetEnabled(boolean enabled); - List getInterfaceList(); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl b/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl deleted file mode 100644 index 751605bb38499..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IEthernetServiceListener.aidl +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2014 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; - -import android.net.IpConfiguration; - -/** @hide */ -oneway interface IEthernetServiceListener -{ - void onEthernetStateChanged(int state); - void onInterfaceStateChanged(String iface, int state, int role, - in IpConfiguration configuration); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IIpSecService.aidl b/packages/ConnectivityT/framework-t/src/android/net/IIpSecService.aidl deleted file mode 100644 index 933256a3b4756..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IIpSecService.aidl +++ /dev/null @@ -1,78 +0,0 @@ -/* -** Copyright 2017, 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; - -import android.net.LinkAddress; -import android.net.Network; -import android.net.IpSecConfig; -import android.net.IpSecUdpEncapResponse; -import android.net.IpSecSpiResponse; -import android.net.IpSecTransformResponse; -import android.net.IpSecTunnelInterfaceResponse; -import android.os.Bundle; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; - -/** - * @hide - */ -interface IIpSecService -{ - IpSecSpiResponse allocateSecurityParameterIndex( - in String destinationAddress, int requestedSpi, in IBinder binder); - - void releaseSecurityParameterIndex(int resourceId); - - IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, in IBinder binder); - - void closeUdpEncapsulationSocket(int resourceId); - - IpSecTunnelInterfaceResponse createTunnelInterface( - in String localAddr, - in String remoteAddr, - in Network underlyingNetwork, - in IBinder binder, - in String callingPackage); - - void addAddressToTunnelInterface( - int tunnelResourceId, - in LinkAddress localAddr, - in String callingPackage); - - void removeAddressFromTunnelInterface( - int tunnelResourceId, - in LinkAddress localAddr, - in String callingPackage); - - void setNetworkForTunnelInterface( - int tunnelResourceId, in Network underlyingNetwork, in String callingPackage); - - void deleteTunnelInterface(int resourceId, in String callingPackage); - - IpSecTransformResponse createTransform( - in IpSecConfig c, in IBinder binder, in String callingPackage); - - void deleteTransform(int transformId); - - void applyTransportModeTransform( - in ParcelFileDescriptor socket, int direction, int transformId); - - void applyTunnelModeTransform( - int tunnelResourceId, int direction, int transformResourceId, in String callingPackage); - - void removeTransportModeTransforms(in ParcelFileDescriptor socket); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl deleted file mode 100644 index 85795ead7aeac..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2021, 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; - -import android.net.EthernetNetworkManagementException; - -/** @hide */ -oneway interface INetworkInterfaceOutcomeReceiver { - void onResult(in String iface); - void onError(in EthernetNetworkManagementException e); -} \ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl deleted file mode 100644 index c86f7fd0890d3..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import android.net.DataUsageRequest; -import android.net.INetworkStatsSession; -import android.net.Network; -import android.net.NetworkStateSnapshot; -import android.net.NetworkStats; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.UnderlyingNetworkInfo; -import android.net.netstats.IUsageCallback; -import android.net.netstats.provider.INetworkStatsProvider; -import android.net.netstats.provider.INetworkStatsProviderCallback; -import android.os.IBinder; -import android.os.Messenger; - -/** {@hide} */ -interface INetworkStatsService { - - /** Start a statistics query session. */ - @UnsupportedAppUsage - INetworkStatsSession openSession(); - - /** Start a statistics query session. If calling package is profile or device owner then it is - * granted automatic access if apiLevel is NetworkStatsManager.API_LEVEL_DPC_ALLOWED. If - * apiLevel is at least NetworkStatsManager.API_LEVEL_REQUIRES_PACKAGE_USAGE_STATS then - * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted - * READ_NETWORK_USAGE_STATS is checked for. - */ - @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) - INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); - - /** Return data layer snapshot of UID network usage. */ - @UnsupportedAppUsage - NetworkStats getDataLayerSnapshotForUid(int uid); - - /** Get the transport NetworkStats for all UIDs since boot. */ - NetworkStats getUidStatsForTransport(int transport); - - /** Return set of any ifaces associated with mobile networks since boot. */ - @UnsupportedAppUsage - String[] getMobileIfaces(); - - /** Increment data layer count of operations performed for UID and tag. */ - void incrementOperationCount(int uid, int tag, int operationCount); - - /** Notify {@code NetworkStatsService} about network status changed. */ - void notifyNetworkStatus( - in Network[] defaultNetworks, - in NetworkStateSnapshot[] snapshots, - in String activeIface, - in UnderlyingNetworkInfo[] underlyingNetworkInfos); - /** Force update of statistics. */ - @UnsupportedAppUsage - void forceUpdate(); - - /** Registers a callback on data usage. */ - DataUsageRequest registerUsageCallback(String callingPackage, - in DataUsageRequest request, in IUsageCallback callback); - - /** Unregisters a callback on data usage. */ - void unregisterUsageRequest(in DataUsageRequest request); - - /** Get the uid stats information since boot */ - long getUidStats(int uid, int type); - - /** Get the iface stats information since boot */ - long getIfaceStats(String iface, int type); - - /** Get the total network stats information since boot */ - long getTotalStats(int type); - - /** Registers a network stats provider */ - INetworkStatsProviderCallback registerNetworkStatsProvider(String tag, - in INetworkStatsProvider provider); - - /** Mark given UID as being in foreground for stats purposes. */ - void noteUidForeground(int uid, boolean uidForeground); - - /** Advise persistence threshold; may be overridden internally. */ - void advisePersistThreshold(long thresholdBytes); - - /** - * Set the warning and limit to all registered custom network stats providers. - * Note that invocation of any interface will be sent to all providers. - */ - void setStatsProviderWarningAndLimitAsync(String iface, long warning, long limit); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl deleted file mode 100644 index ab70be826f8e3..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2012 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; - -import android.net.NetworkStats; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; - -/** {@hide} */ -interface INetworkStatsSession { - - /** Return device aggregated network layer usage summary for traffic that matches template. */ - NetworkStats getDeviceSummaryForNetwork(in NetworkTemplate template, long start, long end); - - /** Return network layer usage summary for traffic that matches template. */ - @UnsupportedAppUsage - NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); - /** Return historical network layer stats for traffic that matches template. */ - @UnsupportedAppUsage - NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields); - /** - * Return historical network layer stats for traffic that matches template, start and end - * timestamp. - */ - NetworkStatsHistory getHistoryIntervalForNetwork(in NetworkTemplate template, int fields, long start, long end); - - /** - * Return network layer usage summary per UID for traffic that matches template. - * - *

The resulting {@code NetworkStats#getElapsedRealtime()} contains time delta between - * {@code start} and {@code end}. - * - * @param template - a predicate to filter netstats. - * @param start - start of the range, timestamp in milliseconds since the epoch. - * @param end - end of the range, timestamp in milliseconds since the epoch. - * @param includeTags - includes data usage tags if true. - */ - @UnsupportedAppUsage - NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); - - /** Return network layer usage summary per UID for tagged traffic that matches template. */ - NetworkStats getTaggedSummaryForAllUid(in NetworkTemplate template, long start, long end); - - /** Return historical network layer stats for specific UID traffic that matches template. */ - @UnsupportedAppUsage - NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields); - /** Return historical network layer stats for specific UID traffic that matches template. */ - NetworkStatsHistory getHistoryIntervalForUid(in NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end); - - /** Return array of uids that have stats and are accessible to the calling user */ - int[] getRelevantUids(); - - @UnsupportedAppUsage - void close(); - -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl deleted file mode 100644 index 14aa0237f24af..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/ITetheredInterfaceCallback.aidl +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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 android.net; - -/** @hide */ -oneway interface ITetheredInterfaceCallback { - void onAvailable(in String iface); - void onUnavailable(); -} \ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java deleted file mode 100644 index 10a22ac360b1d..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecAlgorithm.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (C) 2017 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; - -import android.annotation.NonNull; -import android.annotation.StringDef; -import android.content.res.Resources; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -/** - * This class represents a single algorithm that can be used by an {@link IpSecTransform}. - * - * @see RFC 4301, Security Architecture for the - * Internet Protocol - */ -public final class IpSecAlgorithm implements Parcelable { - private static final String TAG = "IpSecAlgorithm"; - - /** - * Null cipher. - * - * @hide - */ - public static final String CRYPT_NULL = "ecb(cipher_null)"; - - /** - * AES-CBC Encryption/Ciphering Algorithm. - * - *

Valid lengths for this key are {128, 192, 256}. - */ - public static final String CRYPT_AES_CBC = "cbc(aes)"; - - /** - * AES-CTR Encryption/Ciphering Algorithm. - * - *

Valid lengths for keying material are {160, 224, 288}. - * - *

As per RFC3686 (Section - * 5.1), keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit - * nonce. RFC compliance requires that the nonce must be unique per security association. - * - *

This algorithm may be available on the device. Caller MUST check if it is supported before - * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is - * included in the returned algorithm set. The returned algorithm set will not change unless the - * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is - * requested on an unsupported device. - * - *

@see {@link #getSupportedAlgorithms()} - */ - // This algorithm may be available on devices released before Android 12, and is guaranteed - // to be available on devices first shipped with Android 12 or later. - public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))"; - - /** - * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in - * new applications and is provided for legacy compatibility with 3gpp infrastructure. - * - *

Keys for this algorithm must be 128 bits in length. - * - *

Valid truncation lengths are multiples of 8 bits from 96 to 128. - */ - public static final String AUTH_HMAC_MD5 = "hmac(md5)"; - - /** - * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in - * new applications and is provided for legacy compatibility with 3gpp infrastructure. - * - *

Keys for this algorithm must be 160 bits in length. - * - *

Valid truncation lengths are multiples of 8 bits from 96 to 160. - */ - public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; - - /** - * SHA256 HMAC Authentication/Integrity Algorithm. - * - *

Keys for this algorithm must be 256 bits in length. - * - *

Valid truncation lengths are multiples of 8 bits from 96 to 256. - */ - public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; - - /** - * SHA384 HMAC Authentication/Integrity Algorithm. - * - *

Keys for this algorithm must be 384 bits in length. - * - *

Valid truncation lengths are multiples of 8 bits from 192 to 384. - */ - public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; - - /** - * SHA512 HMAC Authentication/Integrity Algorithm. - * - *

Keys for this algorithm must be 512 bits in length. - * - *

Valid truncation lengths are multiples of 8 bits from 256 to 512. - */ - public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; - - /** - * AES-XCBC Authentication/Integrity Algorithm. - * - *

Keys for this algorithm must be 128 bits in length. - * - *

The only valid truncation length is 96 bits. - * - *

This algorithm may be available on the device. Caller MUST check if it is supported before - * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is - * included in the returned algorithm set. The returned algorithm set will not change unless the - * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is - * requested on an unsupported device. - * - *

@see {@link #getSupportedAlgorithms()} - */ - // This algorithm may be available on devices released before Android 12, and is guaranteed - // to be available on devices first shipped with Android 12 or later. - public static final String AUTH_AES_XCBC = "xcbc(aes)"; - - /** - * AES-CMAC Authentication/Integrity Algorithm. - * - *

Keys for this algorithm must be 128 bits in length. - * - *

The only valid truncation length is 96 bits. - * - *

This algorithm may be available on the device. Caller MUST check if it is supported before - * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is - * included in the returned algorithm set. The returned algorithm set will not change unless the - * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is - * requested on an unsupported device. - * - *

@see {@link #getSupportedAlgorithms()} - */ - // This algorithm may be available on devices released before Android 12, and is guaranteed - // to be available on devices first shipped with Android 12 or later. - public static final String AUTH_AES_CMAC = "cmac(aes)"; - - /** - * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm. - * - *

Valid lengths for keying material are {160, 224, 288}. - * - *

As per RFC4106 (Section - * 8.1), keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit - * salt. RFC compliance requires that the salt must be unique per invocation with the same key. - * - *

Valid ICV (truncation) lengths are {64, 96, 128}. - */ - public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; - - /** - * ChaCha20-Poly1305 Authentication/Integrity + Encryption/Ciphering Algorithm. - * - *

Keys for this algorithm must be 288 bits in length. - * - *

As per RFC7634 (Section 2), - * keying material consists of a 256 bit key followed by a 32-bit salt. The salt is fixed per - * security association. - * - *

The only valid ICV (truncation) length is 128 bits. - * - *

This algorithm may be available on the device. Caller MUST check if it is supported before - * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is - * included in the returned algorithm set. The returned algorithm set will not change unless the - * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is - * requested on an unsupported device. - * - *

@see {@link #getSupportedAlgorithms()} - */ - // This algorithm may be available on devices released before Android 12, and is guaranteed - // to be available on devices first shipped with Android 12 or later. - public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)"; - - /** @hide */ - @StringDef({ - CRYPT_AES_CBC, - CRYPT_AES_CTR, - AUTH_HMAC_MD5, - AUTH_HMAC_SHA1, - AUTH_HMAC_SHA256, - AUTH_HMAC_SHA384, - AUTH_HMAC_SHA512, - AUTH_AES_XCBC, - AUTH_AES_CMAC, - AUTH_CRYPT_AES_GCM, - AUTH_CRYPT_CHACHA20_POLY1305 - }) - @Retention(RetentionPolicy.SOURCE) - public @interface AlgorithmName {} - - /** @hide */ - @VisibleForTesting - public static final Map ALGO_TO_REQUIRED_FIRST_SDK = new HashMap<>(); - - private static final int SDK_VERSION_ZERO = 0; - - static { - ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CBC, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_MD5, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA1, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA256, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA384, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO); - - ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S); - } - - private static final Set ENABLED_ALGOS = - Collections.unmodifiableSet(loadAlgos(Resources.getSystem())); - - private final String mName; - private final byte[] mKey; - private final int mTruncLenBits; - - /** - * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are - * defined as constants in this class. - * - *

For algorithms that produce an integrity check value, the truncation length is a required - * parameter. See {@link #IpSecAlgorithm(String algorithm, byte[] key, int truncLenBits)} - * - * @param algorithm name of the algorithm. - * @param key key padded to a multiple of 8 bits. - * @throws IllegalArgumentException if algorithm or key length is invalid. - */ - public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) { - this(algorithm, key, 0); - } - - /** - * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are - * defined as constants in this class. - * - *

This constructor only supports algorithms that use a truncation length. i.e. - * Authentication and Authenticated Encryption algorithms. - * - * @param algorithm name of the algorithm. - * @param key key padded to a multiple of 8 bits. - * @param truncLenBits number of bits of output hash to use. - * @throws IllegalArgumentException if algorithm, key length or truncation length is invalid. - */ - public IpSecAlgorithm( - @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { - mName = algorithm; - mKey = key.clone(); - mTruncLenBits = truncLenBits; - checkValidOrThrow(mName, mKey.length * 8, mTruncLenBits); - } - - /** Get the algorithm name */ - @NonNull - public String getName() { - return mName; - } - - /** Get the key for this algorithm */ - @NonNull - public byte[] getKey() { - return mKey.clone(); - } - - /** Get the truncation length of this algorithm, in bits */ - public int getTruncationLengthBits() { - return mTruncLenBits; - } - - /** Parcelable Implementation */ - public int describeContents() { - return 0; - } - - /** Write to parcel */ - public void writeToParcel(Parcel out, int flags) { - out.writeString(mName); - out.writeByteArray(mKey); - out.writeInt(mTruncLenBits); - } - - /** Parcelable Creator */ - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public IpSecAlgorithm createFromParcel(Parcel in) { - final String name = in.readString(); - final byte[] key = in.createByteArray(); - final int truncLenBits = in.readInt(); - - return new IpSecAlgorithm(name, key, truncLenBits); - } - - public IpSecAlgorithm[] newArray(int size) { - return new IpSecAlgorithm[size]; - } - }; - - /** - * Returns supported IPsec algorithms for the current device. - * - *

Some algorithms may not be supported on old devices. Callers MUST check if an algorithm is - * supported before using it. - */ - @NonNull - public static Set getSupportedAlgorithms() { - return ENABLED_ALGOS; - } - - /** @hide */ - @VisibleForTesting - public static Set loadAlgos(Resources systemResources) { - final Set enabledAlgos = new HashSet<>(); - - // Load and validate the optional algorithm resource. Undefined or duplicate algorithms in - // the resource are not allowed. - final String[] resourceAlgos = systemResources.getStringArray( - android.R.array.config_optionalIpSecAlgorithms); - for (String str : resourceAlgos) { - if (!ALGO_TO_REQUIRED_FIRST_SDK.containsKey(str) || !enabledAlgos.add(str)) { - // This error should be caught by CTS and never be thrown to API callers - throw new IllegalArgumentException("Invalid or repeated algorithm " + str); - } - } - - for (Entry entry : ALGO_TO_REQUIRED_FIRST_SDK.entrySet()) { - if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= entry.getValue()) { - enabledAlgos.add(entry.getKey()); - } - } - - return enabledAlgos; - } - - private static void checkValidOrThrow(String name, int keyLen, int truncLen) { - final boolean isValidLen; - final boolean isValidTruncLen; - - if (!getSupportedAlgorithms().contains(name)) { - throw new IllegalArgumentException("Unsupported algorithm: " + name); - } - - switch (name) { - case CRYPT_AES_CBC: - isValidLen = keyLen == 128 || keyLen == 192 || keyLen == 256; - isValidTruncLen = true; - break; - case CRYPT_AES_CTR: - // The keying material for AES-CTR is a key plus a 32-bit salt - isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; - isValidTruncLen = true; - break; - case AUTH_HMAC_MD5: - isValidLen = keyLen == 128; - isValidTruncLen = truncLen >= 96 && truncLen <= 128; - break; - case AUTH_HMAC_SHA1: - isValidLen = keyLen == 160; - isValidTruncLen = truncLen >= 96 && truncLen <= 160; - break; - case AUTH_HMAC_SHA256: - isValidLen = keyLen == 256; - isValidTruncLen = truncLen >= 96 && truncLen <= 256; - break; - case AUTH_HMAC_SHA384: - isValidLen = keyLen == 384; - isValidTruncLen = truncLen >= 192 && truncLen <= 384; - break; - case AUTH_HMAC_SHA512: - isValidLen = keyLen == 512; - isValidTruncLen = truncLen >= 256 && truncLen <= 512; - break; - case AUTH_AES_XCBC: - isValidLen = keyLen == 128; - isValidTruncLen = truncLen == 96; - break; - case AUTH_AES_CMAC: - isValidLen = keyLen == 128; - isValidTruncLen = truncLen == 96; - break; - case AUTH_CRYPT_AES_GCM: - // The keying material for GCM is a key plus a 32-bit salt - isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; - isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128; - break; - case AUTH_CRYPT_CHACHA20_POLY1305: - // The keying material for ChaCha20Poly1305 is a key plus a 32-bit salt - isValidLen = keyLen == 256 + 32; - isValidTruncLen = truncLen == 128; - break; - default: - // Should never hit here. - throw new IllegalArgumentException("Couldn't find an algorithm: " + name); - } - - if (!isValidLen) { - throw new IllegalArgumentException("Invalid key material keyLength: " + keyLen); - } - if (!isValidTruncLen) { - throw new IllegalArgumentException("Invalid truncation keyLength: " + truncLen); - } - } - - /** @hide */ - public boolean isAuthentication() { - switch (getName()) { - // Fallthrough - case AUTH_HMAC_MD5: - case AUTH_HMAC_SHA1: - case AUTH_HMAC_SHA256: - case AUTH_HMAC_SHA384: - case AUTH_HMAC_SHA512: - case AUTH_AES_XCBC: - case AUTH_AES_CMAC: - return true; - default: - return false; - } - } - - /** @hide */ - public boolean isEncryption() { - switch (getName()) { - case CRYPT_AES_CBC: // fallthrough - case CRYPT_AES_CTR: - return true; - default: - return false; - } - } - - /** @hide */ - public boolean isAead() { - switch (getName()) { - case AUTH_CRYPT_AES_GCM: // fallthrough - case AUTH_CRYPT_CHACHA20_POLY1305: - return true; - default: - return false; - } - } - - @Override - @NonNull - public String toString() { - return new StringBuilder() - .append("{mName=") - .append(mName) - .append(", mTruncLenBits=") - .append(mTruncLenBits) - .append("}") - .toString(); - } - - /** @hide */ - @VisibleForTesting - public static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) { - if (lhs == null || rhs == null) return (lhs == rhs); - return (lhs.mName.equals(rhs.mName) - && Arrays.equals(lhs.mKey, rhs.mKey) - && lhs.mTruncLenBits == rhs.mTruncLenBits); - } -}; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.aidl deleted file mode 100644 index eaefca74d3a05..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2017 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; - -/** @hide */ -parcelable IpSecConfig; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java deleted file mode 100644 index 575c5ed968f8f..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecConfig.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2017 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; - -import android.annotation.Nullable; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.internal.annotations.VisibleForTesting; - -/** - * This class encapsulates all the configuration parameters needed to create IPsec transforms and - * policies. - * - * @hide - */ -public final class IpSecConfig implements Parcelable { - private static final String TAG = "IpSecConfig"; - - // MODE_TRANSPORT or MODE_TUNNEL - private int mMode = IpSecTransform.MODE_TRANSPORT; - - // Preventing this from being null simplifies Java->Native binder - private String mSourceAddress = ""; - - // Preventing this from being null simplifies Java->Native binder - private String mDestinationAddress = ""; - - // The underlying Network that represents the "gateway" Network - // for outbound packets. It may also be used to select packets. - private Network mNetwork; - - // Minimum requirements for identifying a transform - // SPI identifying the IPsec SA in packet processing - // and a destination IP address - private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID; - - // Encryption Algorithm - private IpSecAlgorithm mEncryption; - - // Authentication Algorithm - private IpSecAlgorithm mAuthentication; - - // Authenticated Encryption Algorithm - private IpSecAlgorithm mAuthenticatedEncryption; - - // For tunnel mode IPv4 UDP Encapsulation - // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE - private int mEncapType = IpSecTransform.ENCAP_NONE; - private int mEncapSocketResourceId = IpSecManager.INVALID_RESOURCE_ID; - private int mEncapRemotePort; - - // An interval, in seconds between the NattKeepalive packets - private int mNattKeepaliveInterval; - - // XFRM mark and mask; defaults to 0 (no mark/mask) - private int mMarkValue; - private int mMarkMask; - - // XFRM interface id - private int mXfrmInterfaceId; - - /** Set the mode for this IPsec transform */ - public void setMode(int mode) { - mMode = mode; - } - - /** Set the source IP addres for this IPsec transform */ - public void setSourceAddress(String sourceAddress) { - mSourceAddress = sourceAddress; - } - - /** Set the destination IP address for this IPsec transform */ - public void setDestinationAddress(String destinationAddress) { - mDestinationAddress = destinationAddress; - } - - /** Set the SPI by resource ID */ - public void setSpiResourceId(int resourceId) { - mSpiResourceId = resourceId; - } - - /** Set the encryption algorithm */ - public void setEncryption(IpSecAlgorithm encryption) { - mEncryption = encryption; - } - - /** Set the authentication algorithm */ - public void setAuthentication(IpSecAlgorithm authentication) { - mAuthentication = authentication; - } - - /** Set the authenticated encryption algorithm */ - public void setAuthenticatedEncryption(IpSecAlgorithm authenticatedEncryption) { - mAuthenticatedEncryption = authenticatedEncryption; - } - - /** Set the underlying network that will carry traffic for this transform */ - public void setNetwork(Network network) { - mNetwork = network; - } - - public void setEncapType(int encapType) { - mEncapType = encapType; - } - - public void setEncapSocketResourceId(int resourceId) { - mEncapSocketResourceId = resourceId; - } - - public void setEncapRemotePort(int port) { - mEncapRemotePort = port; - } - - public void setNattKeepaliveInterval(int interval) { - mNattKeepaliveInterval = interval; - } - - /** - * Sets the mark value - * - *

Internal (System server) use only. Marks passed in by users will be overwritten or - * ignored. - */ - public void setMarkValue(int mark) { - mMarkValue = mark; - } - - /** - * Sets the mark mask - * - *

Internal (System server) use only. Marks passed in by users will be overwritten or - * ignored. - */ - public void setMarkMask(int mask) { - mMarkMask = mask; - } - - public void setXfrmInterfaceId(int xfrmInterfaceId) { - mXfrmInterfaceId = xfrmInterfaceId; - } - - // Transport or Tunnel - public int getMode() { - return mMode; - } - - public String getSourceAddress() { - return mSourceAddress; - } - - public int getSpiResourceId() { - return mSpiResourceId; - } - - public String getDestinationAddress() { - return mDestinationAddress; - } - - public IpSecAlgorithm getEncryption() { - return mEncryption; - } - - public IpSecAlgorithm getAuthentication() { - return mAuthentication; - } - - public IpSecAlgorithm getAuthenticatedEncryption() { - return mAuthenticatedEncryption; - } - - public Network getNetwork() { - return mNetwork; - } - - public int getEncapType() { - return mEncapType; - } - - public int getEncapSocketResourceId() { - return mEncapSocketResourceId; - } - - public int getEncapRemotePort() { - return mEncapRemotePort; - } - - public int getNattKeepaliveInterval() { - return mNattKeepaliveInterval; - } - - public int getMarkValue() { - return mMarkValue; - } - - public int getMarkMask() { - return mMarkMask; - } - - public int getXfrmInterfaceId() { - return mXfrmInterfaceId; - } - - // Parcelable Methods - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mMode); - out.writeString(mSourceAddress); - out.writeString(mDestinationAddress); - out.writeParcelable(mNetwork, flags); - out.writeInt(mSpiResourceId); - out.writeParcelable(mEncryption, flags); - out.writeParcelable(mAuthentication, flags); - out.writeParcelable(mAuthenticatedEncryption, flags); - out.writeInt(mEncapType); - out.writeInt(mEncapSocketResourceId); - out.writeInt(mEncapRemotePort); - out.writeInt(mNattKeepaliveInterval); - out.writeInt(mMarkValue); - out.writeInt(mMarkMask); - out.writeInt(mXfrmInterfaceId); - } - - @VisibleForTesting - public IpSecConfig() {} - - /** Copy constructor */ - @VisibleForTesting - public IpSecConfig(IpSecConfig c) { - mMode = c.mMode; - mSourceAddress = c.mSourceAddress; - mDestinationAddress = c.mDestinationAddress; - mNetwork = c.mNetwork; - mSpiResourceId = c.mSpiResourceId; - mEncryption = c.mEncryption; - mAuthentication = c.mAuthentication; - mAuthenticatedEncryption = c.mAuthenticatedEncryption; - mEncapType = c.mEncapType; - mEncapSocketResourceId = c.mEncapSocketResourceId; - mEncapRemotePort = c.mEncapRemotePort; - mNattKeepaliveInterval = c.mNattKeepaliveInterval; - mMarkValue = c.mMarkValue; - mMarkMask = c.mMarkMask; - mXfrmInterfaceId = c.mXfrmInterfaceId; - } - - private IpSecConfig(Parcel in) { - mMode = in.readInt(); - mSourceAddress = in.readString(); - mDestinationAddress = in.readString(); - mNetwork = (Network) in.readParcelable(Network.class.getClassLoader()); - mSpiResourceId = in.readInt(); - mEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mAuthentication = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mAuthenticatedEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mEncapType = in.readInt(); - mEncapSocketResourceId = in.readInt(); - mEncapRemotePort = in.readInt(); - mNattKeepaliveInterval = in.readInt(); - mMarkValue = in.readInt(); - mMarkMask = in.readInt(); - mXfrmInterfaceId = in.readInt(); - } - - @Override - public String toString() { - StringBuilder strBuilder = new StringBuilder(); - strBuilder - .append("{mMode=") - .append(mMode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT") - .append(", mSourceAddress=") - .append(mSourceAddress) - .append(", mDestinationAddress=") - .append(mDestinationAddress) - .append(", mNetwork=") - .append(mNetwork) - .append(", mEncapType=") - .append(mEncapType) - .append(", mEncapSocketResourceId=") - .append(mEncapSocketResourceId) - .append(", mEncapRemotePort=") - .append(mEncapRemotePort) - .append(", mNattKeepaliveInterval=") - .append(mNattKeepaliveInterval) - .append("{mSpiResourceId=") - .append(mSpiResourceId) - .append(", mEncryption=") - .append(mEncryption) - .append(", mAuthentication=") - .append(mAuthentication) - .append(", mAuthenticatedEncryption=") - .append(mAuthenticatedEncryption) - .append(", mMarkValue=") - .append(mMarkValue) - .append(", mMarkMask=") - .append(mMarkMask) - .append(", mXfrmInterfaceId=") - .append(mXfrmInterfaceId) - .append("}"); - - return strBuilder.toString(); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public IpSecConfig createFromParcel(Parcel in) { - return new IpSecConfig(in); - } - - public IpSecConfig[] newArray(int size) { - return new IpSecConfig[size]; - } - }; - - @Override - public boolean equals(@Nullable Object other) { - if (!(other instanceof IpSecConfig)) return false; - final IpSecConfig rhs = (IpSecConfig) other; - return (mMode == rhs.mMode - && mSourceAddress.equals(rhs.mSourceAddress) - && mDestinationAddress.equals(rhs.mDestinationAddress) - && ((mNetwork != null && mNetwork.equals(rhs.mNetwork)) - || (mNetwork == rhs.mNetwork)) - && mEncapType == rhs.mEncapType - && mEncapSocketResourceId == rhs.mEncapSocketResourceId - && mEncapRemotePort == rhs.mEncapRemotePort - && mNattKeepaliveInterval == rhs.mNattKeepaliveInterval - && mSpiResourceId == rhs.mSpiResourceId - && IpSecAlgorithm.equals(mEncryption, rhs.mEncryption) - && IpSecAlgorithm.equals(mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) - && IpSecAlgorithm.equals(mAuthentication, rhs.mAuthentication) - && mMarkValue == rhs.mMarkValue - && mMarkMask == rhs.mMarkMask - && mXfrmInterfaceId == rhs.mXfrmInterfaceId); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java deleted file mode 100644 index 9cb0947b2370e..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * Copyright (C) 2017 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; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.RequiresFeature; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.annotation.SystemService; -import android.annotation.TestApi; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.system.ErrnoException; -import android.system.OsConstants; -import android.util.AndroidException; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import dalvik.system.CloseGuard; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.Socket; -import java.util.Objects; - -/** - * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply - * confidentiality (encryption) and integrity (authentication) to IP traffic. - * - *

Note that not all aspects of IPsec are permitted by this API. Applications may create - * transport mode security associations and apply them to individual sockets. Applications looking - * to create an IPsec VPN should use {@link VpnManager} and {@link Ikev2VpnProfile}. - * - * @see RFC 4301, Security Architecture for the - * Internet Protocol - */ -@SystemService(Context.IPSEC_SERVICE) -public class IpSecManager { - private static final String TAG = "IpSecManager"; - - /** - * Used when applying a transform to direct traffic through an {@link IpSecTransform} - * towards the host. - * - *

See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. - */ - public static final int DIRECTION_IN = 0; - - /** - * Used when applying a transform to direct traffic through an {@link IpSecTransform} - * away from the host. - * - *

See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. - */ - public static final int DIRECTION_OUT = 1; - - /** - * Used when applying a transform to direct traffic through an {@link IpSecTransform} for - * forwarding between interfaces. - * - *

See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static final int DIRECTION_FWD = 2; - - /** @hide */ - @IntDef(value = {DIRECTION_IN, DIRECTION_OUT}) - @Retention(RetentionPolicy.SOURCE) - public @interface PolicyDirection {} - - /** - * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. - * - *

No IPsec packet may contain an SPI of 0. - * - * @hide - */ - @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; - - /** @hide */ - public interface Status { - int OK = 0; - int RESOURCE_UNAVAILABLE = 1; - int SPI_UNAVAILABLE = 2; - } - - /** @hide */ - public static final int INVALID_RESOURCE_ID = -1; - - /** - * Thrown to indicate that a requested SPI is in use. - * - *

The combination of remote {@code InetAddress} and SPI must be unique across all apps on - * one device. If this error is encountered, a new SPI is required before a transform may be - * created. This error can be avoided by calling {@link - * IpSecManager#allocateSecurityParameterIndex}. - */ - public static final class SpiUnavailableException extends AndroidException { - private final int mSpi; - - /** - * Construct an exception indicating that a transform with the given SPI is already in use - * or otherwise unavailable. - * - * @param msg description indicating the colliding SPI - * @param spi the SPI that could not be used due to a collision - */ - SpiUnavailableException(String msg, int spi) { - super(msg + " (spi: " + spi + ")"); - mSpi = spi; - } - - /** Get the SPI that caused a collision. */ - public int getSpi() { - return mSpi; - } - } - - /** - * Thrown to indicate that an IPsec resource is unavailable. - * - *

This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link - * IpSecTransform}, or other system resources. If this exception is thrown, users should release - * allocated objects of the type requested. - */ - public static final class ResourceUnavailableException extends AndroidException { - - ResourceUnavailableException(String msg) { - super(msg); - } - } - - private final Context mContext; - private final IIpSecService mService; - - /** - * This class represents a reserved SPI. - * - *

Objects of this type are used to track reserved security parameter indices. They can be - * obtained by calling {@link IpSecManager#allocateSecurityParameterIndex} and must be released - * by calling {@link #close()} when they are no longer needed. - */ - public static final class SecurityParameterIndex implements AutoCloseable { - private final IIpSecService mService; - private final InetAddress mDestinationAddress; - private final CloseGuard mCloseGuard = CloseGuard.get(); - private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; - private int mResourceId = INVALID_RESOURCE_ID; - - /** Get the underlying SPI held by this object. */ - public int getSpi() { - return mSpi; - } - - /** - * Release an SPI that was previously reserved. - * - *

Release an SPI for use by other users in the system. If a SecurityParameterIndex is - * applied to an IpSecTransform, it will become unusable for future transforms but should - * still be closed to ensure system resources are released. - */ - @Override - public void close() { - try { - mService.releaseSecurityParameterIndex(mResourceId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (Exception e) { - // On close we swallow all random exceptions since failure to close is not - // actionable by the user. - Log.e(TAG, "Failed to close " + this + ", Exception=" + e); - } finally { - mResourceId = INVALID_RESOURCE_ID; - mCloseGuard.close(); - } - } - - /** Check that the SPI was closed properly. */ - @Override - protected void finalize() throws Throwable { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - - close(); - } - - private SecurityParameterIndex( - @NonNull IIpSecService service, InetAddress destinationAddress, int spi) - throws ResourceUnavailableException, SpiUnavailableException { - mService = service; - mDestinationAddress = destinationAddress; - try { - IpSecSpiResponse result = - mService.allocateSecurityParameterIndex( - destinationAddress.getHostAddress(), spi, new Binder()); - - if (result == null) { - throw new NullPointerException("Received null response from IpSecService"); - } - - int status = result.status; - switch (status) { - case Status.OK: - break; - case Status.RESOURCE_UNAVAILABLE: - throw new ResourceUnavailableException( - "No more SPIs may be allocated by this requester."); - case Status.SPI_UNAVAILABLE: - throw new SpiUnavailableException("Requested SPI is unavailable", spi); - default: - throw new RuntimeException( - "Unknown status returned by IpSecService: " + status); - } - mSpi = result.spi; - mResourceId = result.resourceId; - - if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) { - throw new RuntimeException("Invalid SPI returned by IpSecService: " + status); - } - - if (mResourceId == INVALID_RESOURCE_ID) { - throw new RuntimeException( - "Invalid Resource ID returned by IpSecService: " + status); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - mCloseGuard.open("open"); - } - - /** @hide */ - @VisibleForTesting - public int getResourceId() { - return mResourceId; - } - - @Override - public String toString() { - return new StringBuilder() - .append("SecurityParameterIndex{spi=") - .append(mSpi) - .append(",resourceId=") - .append(mResourceId) - .append("}") - .toString(); - } - } - - /** - * Reserve a random SPI for traffic bound to or from the specified destination address. - * - *

If successful, this SPI is guaranteed available until released by a call to {@link - * SecurityParameterIndex#close()}. - * - * @param destinationAddress the destination address for traffic bearing the requested SPI. - * For inbound traffic, the destination should be an address currently assigned on-device. - * @return the reserved SecurityParameterIndex - * @throws ResourceUnavailableException indicating that too many SPIs are - * currently allocated for this user - */ - @NonNull - public SecurityParameterIndex allocateSecurityParameterIndex( - @NonNull InetAddress destinationAddress) throws ResourceUnavailableException { - try { - return new SecurityParameterIndex( - mService, - destinationAddress, - IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); - } catch (ServiceSpecificException e) { - throw rethrowUncheckedExceptionFromServiceSpecificException(e); - } catch (SpiUnavailableException unlikely) { - // Because this function allocates a totally random SPI, it really shouldn't ever - // fail to allocate an SPI; we simply need this because the exception is checked. - throw new ResourceUnavailableException("No SPIs available"); - } - } - - /** - * Reserve the requested SPI for traffic bound to or from the specified destination address. - * - *

If successful, this SPI is guaranteed available until released by a call to {@link - * SecurityParameterIndex#close()}. - * - * @param destinationAddress the destination address for traffic bearing the requested SPI. - * For inbound traffic, the destination should be an address currently assigned on-device. - * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See - * RFC 4303 Section 2.1. - * @return the reserved SecurityParameterIndex - * @throws ResourceUnavailableException indicating that too many SPIs are - * currently allocated for this user - * @throws SpiUnavailableException indicating that the requested SPI could not be - * reserved - */ - @NonNull - public SecurityParameterIndex allocateSecurityParameterIndex( - @NonNull InetAddress destinationAddress, int requestedSpi) - throws SpiUnavailableException, ResourceUnavailableException { - if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { - throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); - } - try { - return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); - } catch (ServiceSpecificException e) { - throw rethrowUncheckedExceptionFromServiceSpecificException(e); - } - } - - /** - * Apply an IPsec transform to a stream socket. - * - *

This applies transport mode encapsulation to the given socket. Once applied, I/O on the - * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, - * unprotected traffic can resume on that socket. - * - *

For security reasons, the destination address of any traffic on the socket must match the - * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any - * other IP address will result in an IOException. In addition, reads and writes on the socket - * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. - * - *

Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an - * applied transform before completion of graceful shutdown may result in the shutdown sequence - * failing to complete. As such, applications requiring graceful shutdown MUST close the socket - * prior to deactivating the applied transform. Socket closure may be performed asynchronously - * (in batches), so the returning of a close function does not guarantee shutdown of a socket. - * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is - * sufficient to ensure shutdown. - * - * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}), - * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST] - * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the - * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped. - * - *

Rekey Procedure

- * - *

When applying a new tranform to a socket in the outbound direction, the previous transform - * will be removed and the new transform will take effect immediately, sending all traffic on - * the new transform; however, when applying a transform in the inbound direction, traffic - * on the old transform will continue to be decrypted and delivered until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey - * procedures where both transforms are valid until both endpoints are using the new transform - * and all in-flight packets have been received. - * - * @param socket a stream socket - * @param direction the direction in which the transform should be applied - * @param transform a transport mode {@code IpSecTransform} - * @throws IOException indicating that the transform could not be applied - */ - public void applyTransportModeTransform(@NonNull Socket socket, - @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { - // Ensure creation of FD. See b/77548890 for more details. - socket.getSoLinger(); - - applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); - } - - /** - * Apply an IPsec transform to a datagram socket. - * - *

This applies transport mode encapsulation to the given socket. Once applied, I/O on the - * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, - * unprotected traffic can resume on that socket. - * - *

For security reasons, the destination address of any traffic on the socket must match the - * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any - * other IP address will result in an IOException. In addition, reads and writes on the socket - * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. - * - *

Rekey Procedure

- * - *

When applying a new tranform to a socket in the outbound direction, the previous transform - * will be removed and the new transform will take effect immediately, sending all traffic on - * the new transform; however, when applying a transform in the inbound direction, traffic - * on the old transform will continue to be decrypted and delivered until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey - * procedures where both transforms are valid until both endpoints are using the new transform - * and all in-flight packets have been received. - * - * @param socket a datagram socket - * @param direction the direction in which the transform should be applied - * @param transform a transport mode {@code IpSecTransform} - * @throws IOException indicating that the transform could not be applied - */ - public void applyTransportModeTransform(@NonNull DatagramSocket socket, - @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { - applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); - } - - /** - * Apply an IPsec transform to a socket. - * - *

This applies transport mode encapsulation to the given socket. Once applied, I/O on the - * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, - * unprotected traffic can resume on that socket. - * - *

For security reasons, the destination address of any traffic on the socket must match the - * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any - * other IP address will result in an IOException. In addition, reads and writes on the socket - * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. - * - *

Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an - * applied transform before completion of graceful shutdown may result in the shutdown sequence - * failing to complete. As such, applications requiring graceful shutdown MUST close the socket - * prior to deactivating the applied transform. Socket closure may be performed asynchronously - * (in batches), so the returning of a close function does not guarantee shutdown of a socket. - * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is - * sufficient to ensure shutdown. - * - * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}), - * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST] - * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the - * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped. - * - *

Rekey Procedure

- * - *

When applying a new tranform to a socket in the outbound direction, the previous transform - * will be removed and the new transform will take effect immediately, sending all traffic on - * the new transform; however, when applying a transform in the inbound direction, traffic - * on the old transform will continue to be decrypted and delivered until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey - * procedures where both transforms are valid until both endpoints are using the new transform - * and all in-flight packets have been received. - * - * @param socket a socket file descriptor - * @param direction the direction in which the transform should be applied - * @param transform a transport mode {@code IpSecTransform} - * @throws IOException indicating that the transform could not be applied - */ - public void applyTransportModeTransform(@NonNull FileDescriptor socket, - @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { - // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() - // constructor takes control and closes the user's FD when we exit the method. - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - mService.applyTransportModeTransform(pfd, direction, transform.getResourceId()); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Remove an IPsec transform from a stream socket. - * - *

Once removed, traffic on the socket will not be encrypted. Removing transforms from a - * socket allows the socket to be reused for communication in the clear. - * - *

If an {@code IpSecTransform} object applied to this socket was deallocated by calling - * {@link IpSecTransform#close()}, then communication on the socket will fail until this method - * is called. - * - * @param socket a socket that previously had a transform applied to it - * @throws IOException indicating that the transform could not be removed from the socket - */ - public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException { - // Ensure creation of FD. See b/77548890 for more details. - socket.getSoLinger(); - - removeTransportModeTransforms(socket.getFileDescriptor$()); - } - - /** - * Remove an IPsec transform from a datagram socket. - * - *

Once removed, traffic on the socket will not be encrypted. Removing transforms from a - * socket allows the socket to be reused for communication in the clear. - * - *

If an {@code IpSecTransform} object applied to this socket was deallocated by calling - * {@link IpSecTransform#close()}, then communication on the socket will fail until this method - * is called. - * - * @param socket a socket that previously had a transform applied to it - * @throws IOException indicating that the transform could not be removed from the socket - */ - public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException { - removeTransportModeTransforms(socket.getFileDescriptor$()); - } - - /** - * Remove an IPsec transform from a socket. - * - *

Once removed, traffic on the socket will not be encrypted. Removing transforms from a - * socket allows the socket to be reused for communication in the clear. - * - *

If an {@code IpSecTransform} object applied to this socket was deallocated by calling - * {@link IpSecTransform#close()}, then communication on the socket will fail until this method - * is called. - * - * @param socket a socket that previously had a transform applied to it - * @throws IOException indicating that the transform could not be removed from the socket - */ - public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException { - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - mService.removeTransportModeTransforms(pfd); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of - * cleanup if a tunneled Network experiences a change in default route. The Network will drop - * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is - * lost, all traffic will drop. - * - *

TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. - * - * @param net a network that currently has transform applied to it. - * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given - * network - * @hide - */ - public void removeTunnelModeTransform(Network net, IpSecTransform transform) {} - - /** - * This class provides access to a UDP encapsulation Socket. - * - *

{@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2 - * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link - * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the - * caller. The caller should not close the {@code FileDescriptor} returned by {@link - * #getFileDescriptor}, but should use {@link #close} instead. - * - *

Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic - * of the next user who binds to that port. To prevent this scenario, these sockets are held - * open by the system so that they may only be closed by calling {@link #close} or when the user - * process exits. - */ - public static final class UdpEncapsulationSocket implements AutoCloseable { - private final ParcelFileDescriptor mPfd; - private final IIpSecService mService; - private int mResourceId = INVALID_RESOURCE_ID; - private final int mPort; - private final CloseGuard mCloseGuard = CloseGuard.get(); - - private UdpEncapsulationSocket(@NonNull IIpSecService service, int port) - throws ResourceUnavailableException, IOException { - mService = service; - try { - IpSecUdpEncapResponse result = - mService.openUdpEncapsulationSocket(port, new Binder()); - switch (result.status) { - case Status.OK: - break; - case Status.RESOURCE_UNAVAILABLE: - throw new ResourceUnavailableException( - "No more Sockets may be allocated by this requester."); - default: - throw new RuntimeException( - "Unknown status returned by IpSecService: " + result.status); - } - mResourceId = result.resourceId; - mPort = result.port; - mPfd = result.fileDescriptor; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - mCloseGuard.open("constructor"); - } - - /** Get the encapsulation socket's file descriptor. */ - public FileDescriptor getFileDescriptor() { - if (mPfd == null) { - return null; - } - return mPfd.getFileDescriptor(); - } - - /** Get the bound port of the wrapped socket. */ - public int getPort() { - return mPort; - } - - /** - * Close this socket. - * - *

This closes the wrapped socket. Open encapsulation sockets count against a user's - * resource limits, and forgetting to close them eventually will result in {@link - * ResourceUnavailableException} being thrown. - */ - @Override - public void close() throws IOException { - try { - mService.closeUdpEncapsulationSocket(mResourceId); - mResourceId = INVALID_RESOURCE_ID; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (Exception e) { - // On close we swallow all random exceptions since failure to close is not - // actionable by the user. - Log.e(TAG, "Failed to close " + this + ", Exception=" + e); - } finally { - mResourceId = INVALID_RESOURCE_ID; - mCloseGuard.close(); - } - - try { - mPfd.close(); - } catch (IOException e) { - Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort); - throw e; - } - } - - /** Check that the socket was closed properly. */ - @Override - protected void finalize() throws Throwable { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } - - /** @hide */ - @SystemApi(client = MODULE_LIBRARIES) - public int getResourceId() { - return mResourceId; - } - - @Override - public String toString() { - return new StringBuilder() - .append("UdpEncapsulationSocket{port=") - .append(mPort) - .append(",resourceId=") - .append(mResourceId) - .append("}") - .toString(); - } - }; - - /** - * Open a socket for UDP encapsulation and bind to the given port. - * - *

See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. - * - * @param port a local UDP port - * @return a socket that is bound to the given port - * @throws IOException indicating that the socket could not be opened or bound - * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open - */ - // Returning a socket in this fashion that has been created and bound by the system - // is the only safe way to ensure that a socket is both accessible to the user and - // safely usable for Encapsulation without allowing a user to possibly unbind from/close - // the port, which could potentially impact the traffic of the next user who binds to that - // socket. - @NonNull - public UdpEncapsulationSocket openUdpEncapsulationSocket(int port) - throws IOException, ResourceUnavailableException { - /* - * Most range checking is done in the service, but this version of the constructor expects - * a valid port number, and zero cannot be checked after being passed to the service. - */ - if (port == 0) { - throw new IllegalArgumentException("Specified port must be a valid port number!"); - } - try { - return new UdpEncapsulationSocket(mService, port); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } - } - - /** - * Open a socket for UDP encapsulation. - * - *

See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. - * - *

The local port of the returned socket can be obtained by calling {@link - * UdpEncapsulationSocket#getPort()}. - * - * @return a socket that is bound to a local port - * @throws IOException indicating that the socket could not be opened or bound - * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open - */ - // Returning a socket in this fashion that has been created and bound by the system - // is the only safe way to ensure that a socket is both accessible to the user and - // safely usable for Encapsulation without allowing a user to possibly unbind from/close - // the port, which could potentially impact the traffic of the next user who binds to that - // socket. - @NonNull - public UdpEncapsulationSocket openUdpEncapsulationSocket() - throws IOException, ResourceUnavailableException { - try { - return new UdpEncapsulationSocket(mService, 0); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } - } - - /** - * This class represents an IpSecTunnelInterface - * - *

IpSecTunnelInterface objects track tunnel interfaces that serve as - * local endpoints for IPsec tunnels. - * - *

Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be - * applied to provide IPsec security to packets sent through the tunnel. While a tunnel - * cannot be used in standalone mode within Android, the higher layers may use the tunnel - * to create Network objects which are accessible to the Android system. - * @hide - */ - @SystemApi - public static final class IpSecTunnelInterface implements AutoCloseable { - private final String mOpPackageName; - private final IIpSecService mService; - private final InetAddress mRemoteAddress; - private final InetAddress mLocalAddress; - private final Network mUnderlyingNetwork; - private final CloseGuard mCloseGuard = CloseGuard.get(); - private String mInterfaceName; - private int mResourceId = INVALID_RESOURCE_ID; - - /** Get the underlying SPI held by this object. */ - @NonNull - public String getInterfaceName() { - return mInterfaceName; - } - - /** - * Add an address to the IpSecTunnelInterface - * - *

Add an address which may be used as the local inner address for - * tunneled traffic. - * - * @param address the local address for traffic inside the tunnel - * @param prefixLen length of the InetAddress prefix - * @hide - */ - @SystemApi - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException { - try { - mService.addAddressToTunnelInterface( - mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Remove an address from the IpSecTunnelInterface - * - *

Remove an address which was previously added to the IpSecTunnelInterface - * - * @param address to be removed - * @param prefixLen length of the InetAddress prefix - * @hide - */ - @SystemApi - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException { - try { - mService.removeAddressFromTunnelInterface( - mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Update the underlying network for this IpSecTunnelInterface. - * - *

This new underlying network will be used for all transforms applied AFTER this call is - * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to - * this tunnel interface, traffic will still use the old SA, and be routed on the old - * underlying network. - * - *

To migrate IPsec tunnel mode traffic, a caller should: - * - *

    - *
  1. Update the IpSecTunnelInterface’s underlying network. - *
  2. Apply {@link IpSecTransform}(s) with matching addresses to this - * IpSecTunnelInterface. - *
- * - * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel. - * This network MUST never be the network exposing this IpSecTunnelInterface, otherwise - * this method will throw an {@link IllegalArgumentException}. If the - * IpSecTunnelInterface is later added to this network, all outbound traffic will be - * blackholed. - */ - // TODO: b/169171001 Update the documentation when transform migration is supported. - // The purpose of making updating network and applying transforms separate is to leave open - // the possibility to support lossless migration procedures. To do that, Android platform - // will need to support multiple inbound tunnel mode transforms, just like it can support - // multiple transport mode transforms. - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void setUnderlyingNetwork(@NonNull Network underlyingNetwork) throws IOException { - try { - mService.setNetworkForTunnelInterface( - mResourceId, underlyingNetwork, mOpPackageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service, - @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, - @NonNull Network underlyingNetwork) - throws ResourceUnavailableException, IOException { - mOpPackageName = ctx.getOpPackageName(); - mService = service; - mLocalAddress = localAddress; - mRemoteAddress = remoteAddress; - mUnderlyingNetwork = underlyingNetwork; - - try { - IpSecTunnelInterfaceResponse result = - mService.createTunnelInterface( - localAddress.getHostAddress(), - remoteAddress.getHostAddress(), - underlyingNetwork, - new Binder(), - mOpPackageName); - switch (result.status) { - case Status.OK: - break; - case Status.RESOURCE_UNAVAILABLE: - throw new ResourceUnavailableException( - "No more tunnel interfaces may be allocated by this requester."); - default: - throw new RuntimeException( - "Unknown status returned by IpSecService: " + result.status); - } - mResourceId = result.resourceId; - mInterfaceName = result.interfaceName; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - mCloseGuard.open("constructor"); - } - - /** - * Delete an IpSecTunnelInterface - * - *

Calling close will deallocate the IpSecTunnelInterface and all of its system - * resources. Any packets bound for this interface either inbound or outbound will - * all be lost. - */ - @Override - public void close() { - try { - mService.deleteTunnelInterface(mResourceId, mOpPackageName); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } catch (Exception e) { - // On close we swallow all random exceptions since failure to close is not - // actionable by the user. - Log.e(TAG, "Failed to close " + this + ", Exception=" + e); - } finally { - mResourceId = INVALID_RESOURCE_ID; - mCloseGuard.close(); - } - } - - /** Check that the Interface was closed properly. */ - @Override - protected void finalize() throws Throwable { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } - - /** @hide */ - @VisibleForTesting - public int getResourceId() { - return mResourceId; - } - - @NonNull - @Override - public String toString() { - return new StringBuilder() - .append("IpSecTunnelInterface{ifname=") - .append(mInterfaceName) - .append(",resourceId=") - .append(mResourceId) - .append("}") - .toString(); - } - } - - /** - * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. - * - *

An application that creates tunnels is responsible for cleaning up the tunnel when the - * underlying network goes away, and the onLost() callback is received. - * - * @param localAddress The local addres of the tunnel - * @param remoteAddress The local addres of the tunnel - * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. - * This network should almost certainly be a network such as WiFi with an L2 address. - * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties - * @throws IOException indicating that the socket could not be opened or bound - * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open - * @hide - */ - @SystemApi - @NonNull - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, - @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) - throws ResourceUnavailableException, IOException { - try { - return new IpSecTunnelInterface( - mContext, mService, localAddress, remoteAddress, underlyingNetwork); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } - } - - /** - * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will - * tunnel all traffic for the given direction through the underlying network's interface with - * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional - * IP header and IPsec Header on all inbound traffic). - *

Applications should probably not use this API directly. - * - * - * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied - * transform. - * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which - * the transform will be used. - * @param transform an {@link IpSecTransform} created in tunnel mode - * @throws IOException indicating that the transform could not be applied due to a lower - * layer failure. - * @hide - */ - @SystemApi - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, - @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { - try { - mService.applyTunnelModeTransform( - tunnel.getResourceId(), direction, - transform.getResourceId(), mContext.getOpPackageName()); - } catch (ServiceSpecificException e) { - throw rethrowCheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @hide - */ - public IpSecTransformResponse createTransform(IpSecConfig config, IBinder binder, - String callingPackage) { - try { - return mService.createTransform(config, binder, callingPackage); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @hide - */ - public void deleteTransform(int resourceId) { - try { - mService.deleteTransform(resourceId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Construct an instance of IpSecManager within an application context. - * - * @param context the application context for this manager - * @hide - */ - public IpSecManager(Context ctx, IIpSecService service) { - mContext = ctx; - mService = Objects.requireNonNull(service, "missing service"); - } - - private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) { - // OsConstants are late binding, so switch statements can't be used. - if (sse.errorCode == OsConstants.EINVAL) { - throw new IllegalArgumentException(sse); - } else if (sse.errorCode == OsConstants.EAGAIN) { - throw new IllegalStateException(sse); - } else if (sse.errorCode == OsConstants.EOPNOTSUPP - || sse.errorCode == OsConstants.EPROTONOSUPPORT) { - throw new UnsupportedOperationException(sse); - } - } - - /** - * Convert an Errno SSE to the correct Unchecked exception type. - * - * This method never actually returns. - */ - // package - static RuntimeException - rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) { - maybeHandleServiceSpecificException(sse); - throw new RuntimeException(sse); - } - - /** - * Convert an Errno SSE to the correct Checked or Unchecked exception type. - * - * This method may throw IOException, or it may throw an unchecked exception; it will never - * actually return. - */ - // package - static IOException rethrowCheckedExceptionFromServiceSpecificException( - ServiceSpecificException sse) throws IOException { - // First see if this is an unchecked exception of a type we know. - // If so, then we prefer the unchecked (specific) type of exception. - maybeHandleServiceSpecificException(sse); - // If not, then all we can do is provide the SSE in the form of an IOException. - throw new ErrnoException( - "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException(); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.aidl deleted file mode 100644 index 6484a0013c53b..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2017 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; - -/** @hide */ -parcelable IpSecSpiResponse; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.java deleted file mode 100644 index f99e570fb7612..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecSpiResponse.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2017 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; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * This class is used to return an SPI and corresponding status from the IpSecService to an - * IpSecManager.SecurityParameterIndex. - * - * @hide - */ -public final class IpSecSpiResponse implements Parcelable { - private static final String TAG = "IpSecSpiResponse"; - - public final int resourceId; - public final int status; - public final int spi; - // Parcelable Methods - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(status); - out.writeInt(resourceId); - out.writeInt(spi); - } - - public IpSecSpiResponse(int inStatus, int inResourceId, int inSpi) { - status = inStatus; - resourceId = inResourceId; - spi = inSpi; - } - - public IpSecSpiResponse(int inStatus) { - if (inStatus == IpSecManager.Status.OK) { - throw new IllegalArgumentException("Valid status implies other args must be provided"); - } - status = inStatus; - resourceId = IpSecManager.INVALID_RESOURCE_ID; - spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - } - - private IpSecSpiResponse(Parcel in) { - status = in.readInt(); - resourceId = in.readInt(); - spi = in.readInt(); - } - - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public IpSecSpiResponse createFromParcel(Parcel in) { - return new IpSecSpiResponse(in); - } - - public IpSecSpiResponse[] newArray(int size) { - return new IpSecSpiResponse[size]; - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java deleted file mode 100644 index 68ae5de4ee706..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransform.java +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Copyright (C) 2017 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; - -import static android.net.IpSecManager.INVALID_RESOURCE_ID; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresFeature; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.ServiceSpecificException; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import dalvik.system.CloseGuard; - -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.InetAddress; -import java.util.Objects; - -/** - * This class represents a transform, which roughly corresponds to an IPsec Security Association. - * - *

Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform} - * object encapsulates the properties and state of an IPsec security association. That includes, - * but is not limited to, algorithm choice, key material, and allocated system resources. - * - * @see RFC 4301, Security Architecture for the - * Internet Protocol - */ -public final class IpSecTransform implements AutoCloseable { - private static final String TAG = "IpSecTransform"; - - /** @hide */ - public static final int MODE_TRANSPORT = 0; - - /** @hide */ - public static final int MODE_TUNNEL = 1; - - /** @hide */ - public static final int ENCAP_NONE = 0; - - /** - * IPsec traffic will be encapsulated within UDP, but with 8 zero-value bytes between the UDP - * header and payload. This prevents traffic from being interpreted as ESP or IKEv2. - * - * @hide - */ - public static final int ENCAP_ESPINUDP_NON_IKE = 1; - - /** - * IPsec traffic will be encapsulated within UDP as per - * RFC 3498. - * - * @hide - */ - public static final int ENCAP_ESPINUDP = 2; - - /** @hide */ - @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NON_IKE}) - @Retention(RetentionPolicy.SOURCE) - public @interface EncapType {} - - /** @hide */ - @VisibleForTesting - public IpSecTransform(Context context, IpSecConfig config) { - mContext = context; - mConfig = new IpSecConfig(config); - mResourceId = INVALID_RESOURCE_ID; - } - - private IpSecManager getIpSecManager(Context context) { - return context.getSystemService(IpSecManager.class); - } - /** - * Checks the result status and throws an appropriate exception if the status is not Status.OK. - */ - private void checkResultStatus(int status) - throws IOException, IpSecManager.ResourceUnavailableException, - IpSecManager.SpiUnavailableException { - switch (status) { - case IpSecManager.Status.OK: - return; - // TODO: Pass Error string back from bundle so that errors can be more specific - case IpSecManager.Status.RESOURCE_UNAVAILABLE: - throw new IpSecManager.ResourceUnavailableException( - "Failed to allocate a new IpSecTransform"); - case IpSecManager.Status.SPI_UNAVAILABLE: - Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved"); - // Fall through - default: - throw new IllegalStateException( - "Failed to Create a Transform with status code " + status); - } - } - - private IpSecTransform activate() - throws IOException, IpSecManager.ResourceUnavailableException, - IpSecManager.SpiUnavailableException { - synchronized (this) { - try { - IpSecTransformResponse result = getIpSecManager(mContext).createTransform( - mConfig, new Binder(), mContext.getOpPackageName()); - int status = result.status; - checkResultStatus(status); - mResourceId = result.resourceId; - Log.d(TAG, "Added Transform with Id " + mResourceId); - mCloseGuard.open("build"); - } catch (ServiceSpecificException e) { - throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e); - } - } - - return this; - } - - /** - * Standard equals. - */ - public boolean equals(@Nullable Object other) { - if (this == other) return true; - if (!(other instanceof IpSecTransform)) return false; - final IpSecTransform rhs = (IpSecTransform) other; - return getConfig().equals(rhs.getConfig()) && mResourceId == rhs.mResourceId; - } - - /** - * Deactivate this {@code IpSecTransform} and free allocated resources. - * - *

Deactivating a transform while it is still applied to a socket will result in errors on - * that socket. Make sure to remove transforms by calling {@link - * IpSecManager#removeTransportModeTransforms}. Note, removing an {@code IpSecTransform} from a - * socket will not deactivate it (because one transform may be applied to multiple sockets). - * - *

It is safe to call this method on a transform that has already been deactivated. - */ - public void close() { - Log.d(TAG, "Removing Transform with Id " + mResourceId); - - // Always safe to attempt cleanup - if (mResourceId == INVALID_RESOURCE_ID) { - mCloseGuard.close(); - return; - } - try { - getIpSecManager(mContext).deleteTransform(mResourceId); - } catch (Exception e) { - // On close we swallow all random exceptions since failure to close is not - // actionable by the user. - Log.e(TAG, "Failed to close " + this + ", Exception=" + e); - } finally { - mResourceId = INVALID_RESOURCE_ID; - mCloseGuard.close(); - } - } - - /** Check that the transform was closed properly. */ - @Override - protected void finalize() throws Throwable { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - close(); - } - - /* Package */ - IpSecConfig getConfig() { - return mConfig; - } - - private final IpSecConfig mConfig; - private int mResourceId; - private final Context mContext; - private final CloseGuard mCloseGuard = CloseGuard.get(); - - /** @hide */ - @VisibleForTesting - public int getResourceId() { - return mResourceId; - } - - /** - * A callback class to provide status information regarding a NAT-T keepalive session - * - *

Use this callback to receive status information regarding a NAT-T keepalive session - * by registering it when calling {@link #startNattKeepalive}. - * - * @hide - */ - public static class NattKeepaliveCallback { - /** The specified {@code Network} is not connected. */ - public static final int ERROR_INVALID_NETWORK = 1; - /** The hardware does not support this request. */ - public static final int ERROR_HARDWARE_UNSUPPORTED = 2; - /** The hardware returned an error. */ - public static final int ERROR_HARDWARE_ERROR = 3; - - /** The requested keepalive was successfully started. */ - public void onStarted() {} - /** The keepalive was successfully stopped. */ - public void onStopped() {} - /** An error occurred. */ - public void onError(int error) {} - } - - /** This class is used to build {@link IpSecTransform} objects. */ - public static class Builder { - private Context mContext; - private IpSecConfig mConfig; - - /** - * Set the encryption algorithm. - * - *

Encryption is mutually exclusive with authenticated encryption. - * - * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. - */ - @NonNull - public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) { - // TODO: throw IllegalArgumentException if algo is not an encryption algorithm. - Objects.requireNonNull(algo); - mConfig.setEncryption(algo); - return this; - } - - /** - * Set the authentication (integrity) algorithm. - * - *

Authentication is mutually exclusive with authenticated encryption. - * - * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. - */ - @NonNull - public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) { - // TODO: throw IllegalArgumentException if algo is not an authentication algorithm. - Objects.requireNonNull(algo); - mConfig.setAuthentication(algo); - return this; - } - - /** - * Set the authenticated encryption algorithm. - * - *

The Authenticated Encryption (AE) class of algorithms are also known as - * Authenticated Encryption with Associated Data (AEAD) algorithms, or Combined mode - * algorithms (as referred to in - * RFC 4301). - * - *

Authenticated encryption is mutually exclusive with encryption and authentication. - * - * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to - * be applied. - */ - @NonNull - public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) { - Objects.requireNonNull(algo); - mConfig.setAuthenticatedEncryption(algo); - return this; - } - - /** - * Add UDP encapsulation to an IPv4 transform. - * - *

This allows IPsec traffic to pass through a NAT. - * - * @see RFC 3948, UDP Encapsulation of IPsec - * ESP Packets - * @see RFC 7296 section 2.23, - * NAT Traversal of IKEv2 - * @param localSocket a socket for sending and receiving encapsulated traffic - * @param remotePort the UDP port number of the remote host that will send and receive - * encapsulated traffic. In the case of IKEv2, this should be port 4500. - */ - @NonNull - public IpSecTransform.Builder setIpv4Encapsulation( - @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { - Objects.requireNonNull(localSocket); - mConfig.setEncapType(ENCAP_ESPINUDP); - if (localSocket.getResourceId() == INVALID_RESOURCE_ID) { - throw new IllegalArgumentException("Invalid UdpEncapsulationSocket"); - } - mConfig.setEncapSocketResourceId(localSocket.getResourceId()); - mConfig.setEncapRemotePort(remotePort); - return this; - } - - /** - * Build a transport mode {@link IpSecTransform}. - * - *

This builds and activates a transport mode transform. Note that an active transform - * will not affect any network traffic until it has been applied to one or more sockets. - * - * @see IpSecManager#applyTransportModeTransform - * @param sourceAddress the source {@code InetAddress} of traffic on sockets that will use - * this transform; this address must belong to the Network used by all sockets that - * utilize this transform; if provided, then only traffic originating from the - * specified source address will be processed. - * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed - * traffic - * @throws IllegalArgumentException indicating that a particular combination of transform - * properties is invalid - * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms - * are active - * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI - * collides with an existing transform - * @throws IOException indicating other errors - */ - @NonNull - public IpSecTransform buildTransportModeTransform( - @NonNull InetAddress sourceAddress, - @NonNull IpSecManager.SecurityParameterIndex spi) - throws IpSecManager.ResourceUnavailableException, - IpSecManager.SpiUnavailableException, IOException { - Objects.requireNonNull(sourceAddress); - Objects.requireNonNull(spi); - if (spi.getResourceId() == INVALID_RESOURCE_ID) { - throw new IllegalArgumentException("Invalid SecurityParameterIndex"); - } - mConfig.setMode(MODE_TRANSPORT); - mConfig.setSourceAddress(sourceAddress.getHostAddress()); - mConfig.setSpiResourceId(spi.getResourceId()); - // FIXME: modifying a builder after calling build can change the built transform. - return new IpSecTransform(mContext, mConfig).activate(); - } - - /** - * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some - * parameters have interdependencies that are checked at build time. - * - * @param sourceAddress the {@link InetAddress} that provides the source address for this - * IPsec tunnel. This is almost certainly an address belonging to the {@link Network} - * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}. - * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed - * traffic - * @throws IllegalArgumentException indicating that a particular combination of transform - * properties is invalid. - * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms - * are active - * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI - * collides with an existing transform - * @throws IOException indicating other errors - * @hide - */ - @SystemApi - @NonNull - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public IpSecTransform buildTunnelModeTransform( - @NonNull InetAddress sourceAddress, - @NonNull IpSecManager.SecurityParameterIndex spi) - throws IpSecManager.ResourceUnavailableException, - IpSecManager.SpiUnavailableException, IOException { - Objects.requireNonNull(sourceAddress); - Objects.requireNonNull(spi); - if (spi.getResourceId() == INVALID_RESOURCE_ID) { - throw new IllegalArgumentException("Invalid SecurityParameterIndex"); - } - mConfig.setMode(MODE_TUNNEL); - mConfig.setSourceAddress(sourceAddress.getHostAddress()); - mConfig.setSpiResourceId(spi.getResourceId()); - return new IpSecTransform(mContext, mConfig).activate(); - } - - /** - * Create a new IpSecTransform.Builder. - * - * @param context current context - */ - public Builder(@NonNull Context context) { - Objects.requireNonNull(context); - mContext = context; - mConfig = new IpSecConfig(); - } - } - - @Override - public String toString() { - return new StringBuilder() - .append("IpSecTransform{resourceId=") - .append(mResourceId) - .append("}") - .toString(); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.aidl deleted file mode 100644 index 546230d5b888a..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2017 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; - -/** @hide */ -parcelable IpSecTransformResponse; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.java deleted file mode 100644 index 363f3165ee650..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTransformResponse.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2017 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; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * This class is used to return an IpSecTransform resource Id and and corresponding status from the - * IpSecService to an IpSecTransform object. - * - * @hide - */ -public final class IpSecTransformResponse implements Parcelable { - private static final String TAG = "IpSecTransformResponse"; - - public final int resourceId; - public final int status; - // Parcelable Methods - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(status); - out.writeInt(resourceId); - } - - public IpSecTransformResponse(int inStatus) { - if (inStatus == IpSecManager.Status.OK) { - throw new IllegalArgumentException("Valid status implies other args must be provided"); - } - status = inStatus; - resourceId = IpSecManager.INVALID_RESOURCE_ID; - } - - public IpSecTransformResponse(int inStatus, int inResourceId) { - status = inStatus; - resourceId = inResourceId; - } - - private IpSecTransformResponse(Parcel in) { - status = in.readInt(); - resourceId = in.readInt(); - } - - @android.annotation.NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public IpSecTransformResponse createFromParcel(Parcel in) { - return new IpSecTransformResponse(in); - } - - public IpSecTransformResponse[] newArray(int size) { - return new IpSecTransformResponse[size]; - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl deleted file mode 100644 index 7239221415cec..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** @hide */ -parcelable IpSecTunnelInterfaceResponse; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java deleted file mode 100644 index 127e30a69394d..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * This class is used to return an IpSecTunnelInterface resource Id and and corresponding status - * from the IpSecService to an IpSecTunnelInterface object. - * - * @hide - */ -public final class IpSecTunnelInterfaceResponse implements Parcelable { - private static final String TAG = "IpSecTunnelInterfaceResponse"; - - public final int resourceId; - public final String interfaceName; - public final int status; - // Parcelable Methods - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(status); - out.writeInt(resourceId); - out.writeString(interfaceName); - } - - public IpSecTunnelInterfaceResponse(int inStatus) { - if (inStatus == IpSecManager.Status.OK) { - throw new IllegalArgumentException("Valid status implies other args must be provided"); - } - status = inStatus; - resourceId = IpSecManager.INVALID_RESOURCE_ID; - interfaceName = ""; - } - - public IpSecTunnelInterfaceResponse(int inStatus, int inResourceId, String inInterfaceName) { - status = inStatus; - resourceId = inResourceId; - interfaceName = inInterfaceName; - } - - private IpSecTunnelInterfaceResponse(Parcel in) { - status = in.readInt(); - resourceId = in.readInt(); - interfaceName = in.readString(); - } - - @android.annotation.NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public IpSecTunnelInterfaceResponse createFromParcel(Parcel in) { - return new IpSecTunnelInterfaceResponse(in); - } - - public IpSecTunnelInterfaceResponse[] newArray(int size) { - return new IpSecTunnelInterfaceResponse[size]; - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.aidl b/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.aidl deleted file mode 100644 index 5e451f3651f10..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2017 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; - -/** @hide */ -parcelable IpSecUdpEncapResponse; diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java deleted file mode 100644 index 732cf198a9cc1..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/IpSecUdpEncapResponse.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2017 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; - -import android.os.Parcel; -import android.os.ParcelFileDescriptor; -import android.os.Parcelable; - -import java.io.FileDescriptor; -import java.io.IOException; - -/** - * This class is used to return a UDP Socket and corresponding status from the IpSecService to an - * IpSecManager.UdpEncapsulationSocket. - * - * @hide - */ -public final class IpSecUdpEncapResponse implements Parcelable { - private static final String TAG = "IpSecUdpEncapResponse"; - - public final int resourceId; - public final int port; - public final int status; - // There is a weird asymmetry with FileDescriptor: you can write a FileDescriptor - // but you read a ParcelFileDescriptor. To circumvent this, when we receive a FD - // from the user, we immediately create a ParcelFileDescriptor DUP, which we invalidate - // on writeParcel() by setting the flag to do close-on-write. - // TODO: tests to ensure this doesn't leak - public final ParcelFileDescriptor fileDescriptor; - - // Parcelable Methods - - @Override - public int describeContents() { - return (fileDescriptor != null) ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(status); - out.writeInt(resourceId); - out.writeInt(port); - out.writeParcelable(fileDescriptor, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); - } - - public IpSecUdpEncapResponse(int inStatus) { - if (inStatus == IpSecManager.Status.OK) { - throw new IllegalArgumentException("Valid status implies other args must be provided"); - } - status = inStatus; - resourceId = IpSecManager.INVALID_RESOURCE_ID; - port = -1; - fileDescriptor = null; // yes I know it's redundant, but readability - } - - public IpSecUdpEncapResponse(int inStatus, int inResourceId, int inPort, FileDescriptor inFd) - throws IOException { - if (inStatus == IpSecManager.Status.OK && inFd == null) { - throw new IllegalArgumentException("Valid status implies FD must be non-null"); - } - status = inStatus; - resourceId = inResourceId; - port = inPort; - fileDescriptor = (status == IpSecManager.Status.OK) ? ParcelFileDescriptor.dup(inFd) : null; - } - - private IpSecUdpEncapResponse(Parcel in) { - status = in.readInt(); - resourceId = in.readInt(); - port = in.readInt(); - fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); - } - - @android.annotation.NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - public IpSecUdpEncapResponse createFromParcel(Parcel in) { - return new IpSecUdpEncapResponse(in); - } - - public IpSecUdpEncapResponse[] newArray(int size) { - return new IpSecUdpEncapResponse[size]; - } - }; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java deleted file mode 100644 index da5f88dc3b7e2..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentity.java +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.app.usage.NetworkStatsManager; -import android.content.Context; -import android.net.wifi.WifiInfo; -import android.service.NetworkIdentityProto; -import android.telephony.TelephonyManager; -import android.util.proto.ProtoOutputStream; - -import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.NetworkCapabilitiesUtils; -import com.android.net.module.util.NetworkIdentityUtils; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Objects; - -/** - * Network definition that includes strong identity. Analogous to combining - * {@link NetworkCapabilities} and an IMSI. - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public class NetworkIdentity { - private static final String TAG = "NetworkIdentity"; - - /** @hide */ - // TODO: Remove this after migrating all callers to use - // {@link NetworkTemplate#NETWORK_TYPE_ALL} instead. - public static final int SUBTYPE_COMBINED = -1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "OEM_MANAGED_" }, flag = true, value = { - NetworkTemplate.OEM_MANAGED_NO, - NetworkTemplate.OEM_MANAGED_PAID, - NetworkTemplate.OEM_MANAGED_PRIVATE - }) - public @interface OemManaged{} - - /** - * Network has no {@code NetworkCapabilities#NET_CAPABILITY_OEM_*}. - * @hide - */ - public static final int OEM_NONE = 0x0; - /** - * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}. - * @hide - */ - public static final int OEM_PAID = 1 << 0; - /** - * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}. - * @hide - */ - public static final int OEM_PRIVATE = 1 << 1; - - private static final long SUPPORTED_OEM_MANAGED_TYPES = OEM_PAID | OEM_PRIVATE; - - final int mType; - final int mRatType; - final int mSubId; - final String mSubscriberId; - final String mWifiNetworkKey; - final boolean mRoaming; - final boolean mMetered; - final boolean mDefaultNetwork; - final int mOemManaged; - - /** @hide */ - public NetworkIdentity( - int type, int ratType, @Nullable String subscriberId, @Nullable String wifiNetworkKey, - boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged, int subId) { - mType = type; - mRatType = ratType; - mSubscriberId = subscriberId; - mWifiNetworkKey = wifiNetworkKey; - mRoaming = roaming; - mMetered = metered; - mDefaultNetwork = defaultNetwork; - mOemManaged = oemManaged; - mSubId = subId; - } - - @Override - public int hashCode() { - return Objects.hash(mType, mRatType, mSubscriberId, mWifiNetworkKey, mRoaming, mMetered, - mDefaultNetwork, mOemManaged, mSubId); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof NetworkIdentity) { - final NetworkIdentity ident = (NetworkIdentity) obj; - return mType == ident.mType && mRatType == ident.mRatType && mRoaming == ident.mRoaming - && Objects.equals(mSubscriberId, ident.mSubscriberId) - && Objects.equals(mWifiNetworkKey, ident.mWifiNetworkKey) - && mMetered == ident.mMetered - && mDefaultNetwork == ident.mDefaultNetwork - && mOemManaged == ident.mOemManaged - && mSubId == ident.mSubId; - } - return false; - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder("{"); - builder.append("type=").append(mType); - builder.append(", ratType="); - if (mRatType == NETWORK_TYPE_ALL) { - builder.append("COMBINED"); - } else { - builder.append(mRatType); - } - if (mSubscriberId != null) { - builder.append(", subscriberId=") - .append(NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); - } - if (mWifiNetworkKey != null) { - builder.append(", wifiNetworkKey=").append(mWifiNetworkKey); - } - if (mRoaming) { - builder.append(", ROAMING"); - } - builder.append(", metered=").append(mMetered); - builder.append(", defaultNetwork=").append(mDefaultNetwork); - builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); - builder.append(", subId=").append(mSubId); - return builder.append("}").toString(); - } - - /** - * Get the human readable representation of a bitfield representing the OEM managed state of a - * network. - */ - static String getOemManagedNames(int oemManaged) { - if (oemManaged == OEM_NONE) { - return "OEM_NONE"; - } - final int[] bitPositions = NetworkCapabilitiesUtils.unpackBits(oemManaged); - final ArrayList oemManagedNames = new ArrayList(); - for (int position : bitPositions) { - oemManagedNames.add(nameOfOemManaged(1 << position)); - } - return String.join(",", oemManagedNames); - } - - private static String nameOfOemManaged(int oemManagedBit) { - switch (oemManagedBit) { - case OEM_PAID: - return "OEM_PAID"; - case OEM_PRIVATE: - return "OEM_PRIVATE"; - default: - return "Invalid(" + oemManagedBit + ")"; - } - } - - /** @hide */ - public void dumpDebug(ProtoOutputStream proto, long tag) { - final long start = proto.start(tag); - - proto.write(NetworkIdentityProto.TYPE, mType); - - // TODO: dump mRatType as well. - - proto.write(NetworkIdentityProto.ROAMING, mRoaming); - proto.write(NetworkIdentityProto.METERED, mMetered); - proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); - proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged); - - proto.end(start); - } - - /** Get the network type of this instance. */ - public int getType() { - return mType; - } - - /** Get the Radio Access Technology(RAT) type of this instance. */ - public int getRatType() { - return mRatType; - } - - /** Get the Subscriber Id of this instance. */ - @Nullable - public String getSubscriberId() { - return mSubscriberId; - } - - /** Get the Wifi Network Key of this instance. See {@link WifiInfo#getNetworkKey()}. */ - @Nullable - public String getWifiNetworkKey() { - return mWifiNetworkKey; - } - - /** @hide */ - // TODO: Remove this function after all callers are removed. - public boolean getRoaming() { - return mRoaming; - } - - /** Return whether this network is roaming. */ - public boolean isRoaming() { - return mRoaming; - } - - /** @hide */ - // TODO: Remove this function after all callers are removed. - public boolean getMetered() { - return mMetered; - } - - /** Return whether this network is metered. */ - public boolean isMetered() { - return mMetered; - } - - /** @hide */ - // TODO: Remove this function after all callers are removed. - public boolean getDefaultNetwork() { - return mDefaultNetwork; - } - - /** Return whether this network is the default network. */ - public boolean isDefaultNetwork() { - return mDefaultNetwork; - } - - /** Get the OEM managed type of this instance. */ - public int getOemManaged() { - return mOemManaged; - } - - /** Get the SubId of this instance. */ - public int getSubId() { - return mSubId; - } - - /** - * Assemble a {@link NetworkIdentity} from the passed arguments. - * - * This methods builds an identity based on the capabilities of the network in the - * snapshot and other passed arguments. The identity is used as a key to record data usage. - * - * @param snapshot the snapshot of network state. See {@link NetworkStateSnapshot}. - * @param defaultNetwork whether the network is a default network. - * @param ratType the Radio Access Technology(RAT) type of the network. Or - * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if not applicable. - * See {@code TelephonyManager.NETWORK_TYPE_*}. - * @hide - * @deprecated See {@link NetworkIdentity.Builder}. - */ - // TODO: Remove this after all callers are migrated to use new Api. - @Deprecated - @NonNull - public static NetworkIdentity buildNetworkIdentity(Context context, - @NonNull NetworkStateSnapshot snapshot, boolean defaultNetwork, int ratType) { - final NetworkIdentity.Builder builder = new NetworkIdentity.Builder() - .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork) - .setSubId(snapshot.getSubId()); - if (snapshot.getLegacyType() == TYPE_MOBILE && ratType != NETWORK_TYPE_ALL) { - builder.setRatType(ratType); - } - return builder.build(); - } - - /** - * Builds a bitfield of {@code NetworkIdentity.OEM_*} based on {@link NetworkCapabilities}. - * @hide - */ - public static int getOemBitfield(@NonNull NetworkCapabilities nc) { - int oemManaged = OEM_NONE; - - if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID)) { - oemManaged |= OEM_PAID; - } - if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE)) { - oemManaged |= OEM_PRIVATE; - } - - return oemManaged; - } - - /** @hide */ - public static int compare(@NonNull NetworkIdentity left, @NonNull NetworkIdentity right) { - Objects.requireNonNull(right); - int res = Integer.compare(left.mType, right.mType); - if (res == 0) { - res = Integer.compare(left.mRatType, right.mRatType); - } - if (res == 0 && left.mSubscriberId != null && right.mSubscriberId != null) { - res = left.mSubscriberId.compareTo(right.mSubscriberId); - } - if (res == 0 && left.mWifiNetworkKey != null && right.mWifiNetworkKey != null) { - res = left.mWifiNetworkKey.compareTo(right.mWifiNetworkKey); - } - if (res == 0) { - res = Boolean.compare(left.mRoaming, right.mRoaming); - } - if (res == 0) { - res = Boolean.compare(left.mMetered, right.mMetered); - } - if (res == 0) { - res = Boolean.compare(left.mDefaultNetwork, right.mDefaultNetwork); - } - if (res == 0) { - res = Integer.compare(left.mOemManaged, right.mOemManaged); - } - if (res == 0) { - res = Integer.compare(left.mSubId, right.mSubId); - } - return res; - } - - /** - * Builder class for {@link NetworkIdentity}. - */ - public static final class Builder { - // Need to be synchronized with ConnectivityManager. - // TODO: Use {@link ConnectivityManager#MAX_NETWORK_TYPE} when this file is in the module. - private static final int MAX_NETWORK_TYPE = 18; // TYPE_TEST - private static final int MIN_NETWORK_TYPE = TYPE_MOBILE; - - private int mType; - private int mRatType; - private String mSubscriberId; - private String mWifiNetworkKey; - private boolean mRoaming; - private boolean mMetered; - private boolean mDefaultNetwork; - private int mOemManaged; - private int mSubId; - - /** - * Creates a new Builder. - */ - public Builder() { - // Initialize with default values. Will be overwritten by setters. - mType = ConnectivityManager.TYPE_NONE; - mRatType = NetworkTemplate.NETWORK_TYPE_ALL; - mSubscriberId = null; - mWifiNetworkKey = null; - mRoaming = false; - mMetered = false; - mDefaultNetwork = false; - mOemManaged = NetworkTemplate.OEM_MANAGED_NO; - mSubId = INVALID_SUBSCRIPTION_ID; - } - - /** - * Add an {@link NetworkStateSnapshot} into the {@link NetworkIdentity} instance. - * This is a useful shorthand that will read from the snapshot and set the - * following fields, if they are set in the snapshot : - * - type - * - subscriberId - * - roaming - * - metered - * - oemManaged - * - wifiNetworkKey - * - * @param snapshot The target {@link NetworkStateSnapshot} object. - * @return The builder object. - */ - @SuppressLint("MissingGetterMatchingBuilder") - @NonNull - public Builder setNetworkStateSnapshot(@NonNull NetworkStateSnapshot snapshot) { - setType(snapshot.getLegacyType()); - - setSubscriberId(snapshot.getSubscriberId()); - setRoaming(!snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)); - setMetered(!(snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED) - || snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED))); - - setOemManaged(getOemBitfield(snapshot.getNetworkCapabilities())); - - if (mType == TYPE_WIFI) { - final TransportInfo transportInfo = snapshot.getNetworkCapabilities() - .getTransportInfo(); - if (transportInfo instanceof WifiInfo) { - final WifiInfo info = (WifiInfo) transportInfo; - setWifiNetworkKey(info.getNetworkKey()); - } - } - return this; - } - - /** - * Set the network type of the network. - * - * @param type the network type. See {@link ConnectivityManager#TYPE_*}. - * - * @return this builder. - */ - @NonNull - public Builder setType(int type) { - // Include TYPE_NONE for compatibility, type field might not be filled by some - // networks such as test networks. - if ((type < MIN_NETWORK_TYPE || MAX_NETWORK_TYPE < type) - && type != ConnectivityManager.TYPE_NONE) { - throw new IllegalArgumentException("Invalid network type: " + type); - } - mType = type; - return this; - } - - /** - * Set the Radio Access Technology(RAT) type of the network. - * - * No RAT type is specified by default. Call clearRatType to reset. - * - * @param ratType the Radio Access Technology(RAT) type if applicable. See - * {@code TelephonyManager.NETWORK_TYPE_*}. - * - * @return this builder. - */ - @NonNull - public Builder setRatType(int ratType) { - if (!CollectionUtils.contains(TelephonyManager.getAllNetworkTypes(), ratType) - && ratType != TelephonyManager.NETWORK_TYPE_UNKNOWN - && ratType != NetworkStatsManager.NETWORK_TYPE_5G_NSA) { - throw new IllegalArgumentException("Invalid ratType " + ratType); - } - mRatType = ratType; - return this; - } - - /** - * Clear the Radio Access Technology(RAT) type of the network. - * - * @return this builder. - */ - @NonNull - public Builder clearRatType() { - mRatType = NetworkTemplate.NETWORK_TYPE_ALL; - return this; - } - - /** - * Set the Subscriber Id. - * - * @param subscriberId the Subscriber Id of the network. Or null if not applicable. - * @return this builder. - */ - @NonNull - public Builder setSubscriberId(@Nullable String subscriberId) { - mSubscriberId = subscriberId; - return this; - } - - /** - * Set the Wifi Network Key. - * - * @param wifiNetworkKey Wifi Network Key of the network, - * see {@link WifiInfo#getNetworkKey()}. - * Or null if not applicable. - * @return this builder. - */ - @NonNull - public Builder setWifiNetworkKey(@Nullable String wifiNetworkKey) { - mWifiNetworkKey = wifiNetworkKey; - return this; - } - - /** - * Set whether this network is roaming. - * - * This field is false by default. Call with false to reset. - * - * @param roaming the roaming status of the network. - * @return this builder. - */ - @NonNull - public Builder setRoaming(boolean roaming) { - mRoaming = roaming; - return this; - } - - /** - * Set whether this network is metered. - * - * This field is false by default. Call with false to reset. - * - * @param metered the meteredness of the network. - * @return this builder. - */ - @NonNull - public Builder setMetered(boolean metered) { - mMetered = metered; - return this; - } - - /** - * Set whether this network is the default network. - * - * This field is false by default. Call with false to reset. - * - * @param defaultNetwork the default network status of the network. - * @return this builder. - */ - @NonNull - public Builder setDefaultNetwork(boolean defaultNetwork) { - mDefaultNetwork = defaultNetwork; - return this; - } - - /** - * Set the OEM managed type. - * - * @param oemManaged Type of OEM managed network or unmanaged networks. - * See {@code NetworkTemplate#OEM_MANAGED_*}. - * @return this builder. - */ - @NonNull - public Builder setOemManaged(@OemManaged int oemManaged) { - // Assert input does not contain illegal oemManage bits. - if ((~SUPPORTED_OEM_MANAGED_TYPES & oemManaged) != 0) { - throw new IllegalArgumentException("Invalid value for OemManaged : " + oemManaged); - } - mOemManaged = oemManaged; - return this; - } - - /** - * Set the Subscription Id. - * - * @param subId the Subscription Id of the network. Or INVALID_SUBSCRIPTION_ID if not - * applicable. - * @return this builder. - */ - @NonNull - public Builder setSubId(int subId) { - mSubId = subId; - return this; - } - - private void ensureValidParameters() { - // Assert non-mobile network cannot have a ratType. - if (mType != TYPE_MOBILE && mRatType != NetworkTemplate.NETWORK_TYPE_ALL) { - throw new IllegalArgumentException( - "Invalid ratType " + mRatType + " for type " + mType); - } - - // Assert non-wifi network cannot have a wifi network key. - if (mType != TYPE_WIFI && mWifiNetworkKey != null) { - throw new IllegalArgumentException("Invalid wifi network key for type " + mType); - } - } - - /** - * Builds the instance of the {@link NetworkIdentity}. - * - * @return the built instance of {@link NetworkIdentity}. - */ - @NonNull - public NetworkIdentity build() { - ensureValidParameters(); - return new NetworkIdentity(mType, mRatType, mSubscriberId, mWifiNetworkKey, - mRoaming, mMetered, mDefaultNetwork, mOemManaged, mSubId); - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java deleted file mode 100644 index ad3a958a680ee..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkIdentitySet.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; - -import android.annotation.NonNull; -import android.service.NetworkIdentitySetProto; -import android.util.proto.ProtoOutputStream; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -/** - * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} - * active on that interface. - * - * @hide - */ -public class NetworkIdentitySet extends HashSet { - private static final int VERSION_INIT = 1; - private static final int VERSION_ADD_ROAMING = 2; - private static final int VERSION_ADD_NETWORK_ID = 3; - private static final int VERSION_ADD_METERED = 4; - private static final int VERSION_ADD_DEFAULT_NETWORK = 5; - private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6; - private static final int VERSION_ADD_SUB_ID = 7; - - /** - * Construct a {@link NetworkIdentitySet} object. - */ - public NetworkIdentitySet() { - super(); - } - - /** @hide */ - public NetworkIdentitySet(@NonNull Set ident) { - super(ident); - } - - /** @hide */ - public NetworkIdentitySet(DataInput in) throws IOException { - final int version = in.readInt(); - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - if (version <= VERSION_INIT) { - final int ignored = in.readInt(); - } - final int type = in.readInt(); - final int ratType = in.readInt(); - final String subscriberId = readOptionalString(in); - final String networkId; - if (version >= VERSION_ADD_NETWORK_ID) { - networkId = readOptionalString(in); - } else { - networkId = null; - } - final boolean roaming; - if (version >= VERSION_ADD_ROAMING) { - roaming = in.readBoolean(); - } else { - roaming = false; - } - - final boolean metered; - if (version >= VERSION_ADD_METERED) { - metered = in.readBoolean(); - } else { - // If this is the old data and the type is mobile, treat it as metered. (Note that - // if this is a mobile network, TYPE_MOBILE is the only possible type that could be - // used.) - metered = (type == TYPE_MOBILE); - } - - final boolean defaultNetwork; - if (version >= VERSION_ADD_DEFAULT_NETWORK) { - defaultNetwork = in.readBoolean(); - } else { - defaultNetwork = true; - } - - final int oemNetCapabilities; - if (version >= VERSION_ADD_OEM_MANAGED_NETWORK) { - oemNetCapabilities = in.readInt(); - } else { - oemNetCapabilities = NetworkIdentity.OEM_NONE; - } - - final int subId; - if (version >= VERSION_ADD_SUB_ID) { - subId = in.readInt(); - } else { - subId = INVALID_SUBSCRIPTION_ID; - } - - add(new NetworkIdentity(type, ratType, subscriberId, networkId, roaming, metered, - defaultNetwork, oemNetCapabilities, subId)); - } - } - - /** - * Method to serialize this object into a {@code DataOutput}. - * @hide - */ - public void writeToStream(DataOutput out) throws IOException { - out.writeInt(VERSION_ADD_SUB_ID); - out.writeInt(size()); - for (NetworkIdentity ident : this) { - out.writeInt(ident.getType()); - out.writeInt(ident.getRatType()); - writeOptionalString(out, ident.getSubscriberId()); - writeOptionalString(out, ident.getWifiNetworkKey()); - out.writeBoolean(ident.isRoaming()); - out.writeBoolean(ident.isMetered()); - out.writeBoolean(ident.isDefaultNetwork()); - out.writeInt(ident.getOemManaged()); - out.writeInt(ident.getSubId()); - } - } - - /** - * @return whether any {@link NetworkIdentity} in this set is considered metered. - * @hide - */ - public boolean isAnyMemberMetered() { - if (isEmpty()) { - return false; - } - for (NetworkIdentity ident : this) { - if (ident.isMetered()) { - return true; - } - } - return false; - } - - /** - * @return whether any {@link NetworkIdentity} in this set is considered roaming. - * @hide - */ - public boolean isAnyMemberRoaming() { - if (isEmpty()) { - return false; - } - for (NetworkIdentity ident : this) { - if (ident.isRoaming()) { - return true; - } - } - return false; - } - - /** - * @return whether any {@link NetworkIdentity} in this set is considered on the default - * network. - * @hide - */ - public boolean areAllMembersOnDefaultNetwork() { - if (isEmpty()) { - return true; - } - for (NetworkIdentity ident : this) { - if (!ident.isDefaultNetwork()) { - return false; - } - } - return true; - } - - private static void writeOptionalString(DataOutput out, String value) throws IOException { - if (value != null) { - out.writeByte(1); - out.writeUTF(value); - } else { - out.writeByte(0); - } - } - - private static String readOptionalString(DataInput in) throws IOException { - if (in.readByte() != 0) { - return in.readUTF(); - } else { - return null; - } - } - - public static int compare(@NonNull NetworkIdentitySet left, @NonNull NetworkIdentitySet right) { - Objects.requireNonNull(left); - Objects.requireNonNull(right); - if (left.isEmpty()) return -1; - if (right.isEmpty()) return 1; - - final NetworkIdentity leftIdent = left.iterator().next(); - final NetworkIdentity rightIdent = right.iterator().next(); - return NetworkIdentity.compare(leftIdent, rightIdent); - } - - /** - * Method to dump this object into proto debug file. - * @hide - */ - public void dumpDebug(ProtoOutputStream proto, long tag) { - final long start = proto.start(tag); - - for (NetworkIdentity ident : this) { - ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES); - } - - proto.end(start); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java deleted file mode 100644 index d3f785a8f983b..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStateSnapshot.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.net.module.util.NetworkIdentityUtils; - -import java.util.Objects; - -/** - * Snapshot of network state. - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public final class NetworkStateSnapshot implements Parcelable { - /** The network associated with this snapshot. */ - @NonNull - private final Network mNetwork; - - /** The {@link NetworkCapabilities} of the network associated with this snapshot. */ - @NonNull - private final NetworkCapabilities mNetworkCapabilities; - - /** The {@link LinkProperties} of the network associated with this snapshot. */ - @NonNull - private final LinkProperties mLinkProperties; - - /** - * The Subscriber Id of the network associated with this snapshot. See - * {@link android.telephony.TelephonyManager#getSubscriberId()}. - */ - @Nullable - private final String mSubscriberId; - - /** - * The legacy type of the network associated with this snapshot. See - * {@code ConnectivityManager#TYPE_*}. - */ - private final int mLegacyType; - - public NetworkStateSnapshot(@NonNull Network network, - @NonNull NetworkCapabilities networkCapabilities, - @NonNull LinkProperties linkProperties, - @Nullable String subscriberId, int legacyType) { - mNetwork = Objects.requireNonNull(network); - mNetworkCapabilities = Objects.requireNonNull(networkCapabilities); - mLinkProperties = Objects.requireNonNull(linkProperties); - mSubscriberId = subscriberId; - mLegacyType = legacyType; - } - - /** @hide */ - public NetworkStateSnapshot(@NonNull Parcel in) { - mNetwork = in.readParcelable(null); - mNetworkCapabilities = in.readParcelable(null); - mLinkProperties = in.readParcelable(null); - mSubscriberId = in.readString(); - mLegacyType = in.readInt(); - } - - /** Get the network associated with this snapshot */ - @NonNull - public Network getNetwork() { - return mNetwork; - } - - /** Get {@link NetworkCapabilities} of the network associated with this snapshot. */ - @NonNull - public NetworkCapabilities getNetworkCapabilities() { - return mNetworkCapabilities; - } - - /** Get the {@link LinkProperties} of the network associated with this snapshot. */ - @NonNull - public LinkProperties getLinkProperties() { - return mLinkProperties; - } - - /** - * Get the Subscriber Id of the network associated with this snapshot. - * @deprecated Please use #getSubId, which doesn't return personally identifiable - * information. - */ - @Deprecated - @Nullable - public String getSubscriberId() { - return mSubscriberId; - } - - /** Get the subId of the network associated with this snapshot. */ - public int getSubId() { - if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { - final NetworkSpecifier spec = mNetworkCapabilities.getNetworkSpecifier(); - if (spec instanceof TelephonyNetworkSpecifier) { - return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); - } - } - return INVALID_SUBSCRIPTION_ID; - } - - - /** - * Get the legacy type of the network associated with this snapshot. - * @return the legacy network type. See {@code ConnectivityManager#TYPE_*}. - */ - public int getLegacyType() { - return mLegacyType; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeParcelable(mNetwork, flags); - out.writeParcelable(mNetworkCapabilities, flags); - out.writeParcelable(mLinkProperties, flags); - out.writeString(mSubscriberId); - out.writeInt(mLegacyType); - } - - @NonNull - public static final Creator CREATOR = - new Creator() { - @NonNull - @Override - public NetworkStateSnapshot createFromParcel(@NonNull Parcel in) { - return new NetworkStateSnapshot(in); - } - - @NonNull - @Override - public NetworkStateSnapshot[] newArray(int size) { - return new NetworkStateSnapshot[size]; - } - }; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof NetworkStateSnapshot)) return false; - NetworkStateSnapshot that = (NetworkStateSnapshot) o; - return mLegacyType == that.mLegacyType - && Objects.equals(mNetwork, that.mNetwork) - && Objects.equals(mNetworkCapabilities, that.mNetworkCapabilities) - && Objects.equals(mLinkProperties, that.mLinkProperties) - && Objects.equals(mSubscriberId, that.mSubscriberId); - } - - @Override - public int hashCode() { - return Objects.hash(mNetwork, - mNetworkCapabilities, mLinkProperties, mSubscriberId, mLegacyType); - } - - @Override - public String toString() { - return "NetworkStateSnapshot{" - + "network=" + mNetwork - + ", networkCapabilities=" + mNetworkCapabilities - + ", linkProperties=" + mLinkProperties - + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(mSubscriberId) + '\'' - + ", legacyType=" + mLegacyType - + '}'; - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java deleted file mode 100644 index 06f2a621bcae7..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java +++ /dev/null @@ -1,1834 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.os.Process; -import android.os.SystemClock; -import android.text.TextUtils; -import android.util.SparseBooleanArray; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.CollectionUtils; - -import libcore.util.EmptyArray; - -import java.io.CharArrayWriter; -import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Predicate; - -/** - * Collection of active network statistics. Can contain summary details across - * all interfaces, or details with per-UID granularity. Internally stores data - * as a large table, closely matching {@code /proc/} data format. This structure - * optimizes for rapid in-memory comparison, but consider using - * {@link NetworkStatsHistory} when persisting. - * - * @hide - */ -// @NotThreadSafe -@SystemApi -public final class NetworkStats implements Parcelable, Iterable { - private static final String TAG = "NetworkStats"; - - /** - * {@link #iface} value when interface details unavailable. - * @hide - */ - @Nullable public static final String IFACE_ALL = null; - - /** - * Virtual network interface for video telephony. This is for VT data usage counting - * purpose. - */ - public static final String IFACE_VT = "vt_data0"; - - /** {@link #uid} value when UID details unavailable. */ - public static final int UID_ALL = -1; - /** Special UID value for data usage by tethering. */ - public static final int UID_TETHERING = -5; - - /** - * {@link #tag} value matching any tag. - * @hide - */ - // TODO: Rename TAG_ALL to TAG_ANY. - public static final int TAG_ALL = -1; - /** {@link #set} value for all sets combined, not including debug sets. */ - public static final int SET_ALL = -1; - /** {@link #set} value where background data is accounted. */ - public static final int SET_DEFAULT = 0; - /** {@link #set} value where foreground data is accounted. */ - public static final int SET_FOREGROUND = 1; - /** - * All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. - * @hide - */ - public static final int SET_DEBUG_START = 1000; - /** - * Debug {@link #set} value when the VPN stats are moved in. - * @hide - */ - public static final int SET_DBG_VPN_IN = 1001; - /** - * Debug {@link #set} value when the VPN stats are moved out of a vpn UID. - * @hide - */ - public static final int SET_DBG_VPN_OUT = 1002; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "SET_" }, value = { - SET_ALL, - SET_DEFAULT, - SET_FOREGROUND, - }) - public @interface State { - } - - /** - * Include all interfaces when filtering - * @hide - */ - public @Nullable static final String[] INTERFACES_ALL = null; - - /** {@link #tag} value for total data across all tags. */ - // TODO: Rename TAG_NONE to TAG_ALL. - public static final int TAG_NONE = 0; - - /** {@link #metered} value to account for all metered states. */ - public static final int METERED_ALL = -1; - /** {@link #metered} value where native, unmetered data is accounted. */ - public static final int METERED_NO = 0; - /** {@link #metered} value where metered data is accounted. */ - public static final int METERED_YES = 1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "METERED_" }, value = { - METERED_ALL, - METERED_NO, - METERED_YES - }) - public @interface Meteredness { - } - - - /** {@link #roaming} value to account for all roaming states. */ - public static final int ROAMING_ALL = -1; - /** {@link #roaming} value where native, non-roaming data is accounted. */ - public static final int ROAMING_NO = 0; - /** {@link #roaming} value where roaming data is accounted. */ - public static final int ROAMING_YES = 1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "ROAMING_" }, value = { - ROAMING_ALL, - ROAMING_NO, - ROAMING_YES - }) - public @interface Roaming { - } - - /** {@link #onDefaultNetwork} value to account for all default network states. */ - public static final int DEFAULT_NETWORK_ALL = -1; - /** {@link #onDefaultNetwork} value to account for usage while not the default network. */ - public static final int DEFAULT_NETWORK_NO = 0; - /** {@link #onDefaultNetwork} value to account for usage while the default network. */ - public static final int DEFAULT_NETWORK_YES = 1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "DEFAULT_NETWORK_" }, value = { - DEFAULT_NETWORK_ALL, - DEFAULT_NETWORK_NO, - DEFAULT_NETWORK_YES - }) - public @interface DefaultNetwork { - } - - /** - * Denotes a request for stats at the interface level. - * @hide - */ - public static final int STATS_PER_IFACE = 0; - /** - * Denotes a request for stats at the interface and UID level. - * @hide - */ - public static final int STATS_PER_UID = 1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "STATS_PER_" }, value = { - STATS_PER_IFACE, - STATS_PER_UID - }) - public @interface StatsType { - } - - private static final String CLATD_INTERFACE_PREFIX = "v4-"; - // Delta between IPv4 header (20b) and IPv6 header (40b). - // Used for correct stats accounting on clatd interfaces. - private static final int IPV4V6_HEADER_DELTA = 20; - - // TODO: move fields to "mVariable" notation - - /** - * {@link SystemClock#elapsedRealtime()} timestamp in milliseconds when this data was - * generated. - * It's a timestamps delta when {@link #subtract()}, - * {@code INetworkStatsSession#getSummaryForAllUid()} methods are used. - */ - private long elapsedRealtime; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int size; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int capacity; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private String[] iface; - @UnsupportedAppUsage - private int[] uid; - @UnsupportedAppUsage - private int[] set; - @UnsupportedAppUsage - private int[] tag; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int[] metered; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int[] roaming; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int[] defaultNetwork; - @UnsupportedAppUsage - private long[] rxBytes; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long[] rxPackets; - @UnsupportedAppUsage - private long[] txBytes; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long[] txPackets; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long[] operations; - - /** - * Basic element of network statistics. Contains the number of packets and number of bytes - * transferred on both directions in a given set of conditions. See - * {@link Entry#Entry(String, int, int, int, int, int, int, long, long, long, long, long)}. - * - * @hide - */ - @SystemApi - public static class Entry { - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public String iface; - /** @hide */ - @UnsupportedAppUsage - public int uid; - /** @hide */ - @UnsupportedAppUsage - public int set; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int tag; - /** - * Note that this is only populated w/ the default value when read from /proc or written - * to disk. We merge in the correct value when reporting this value to clients of - * getSummary(). - * @hide - */ - public int metered; - /** - * Note that this is only populated w/ the default value when read from /proc or written - * to disk. We merge in the correct value when reporting this value to clients of - * getSummary(). - * @hide - */ - public int roaming; - /** - * Note that this is only populated w/ the default value when read from /proc or written - * to disk. We merge in the correct value when reporting this value to clients of - * getSummary(). - * @hide - */ - public int defaultNetwork; - /** @hide */ - @UnsupportedAppUsage - public long rxBytes; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long rxPackets; - /** @hide */ - @UnsupportedAppUsage - public long txBytes; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long txPackets; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long operations; - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public Entry() { - this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); - } - - /** @hide */ - public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, - operations); - } - - /** @hide */ - public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, - long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, - rxBytes, rxPackets, txBytes, txPackets, operations); - } - - /** - * Construct a {@link Entry} object by giving statistics of packet and byte transferred on - * both direction, and associated with a set of given conditions. - * - * @param iface interface name of this {@link Entry}. Or null if not specified. - * @param uid uid of this {@link Entry}. {@link #UID_TETHERING} if this {@link Entry} is - * for tethering. Or {@link #UID_ALL} if this {@link NetworkStats} is only - * counting iface stats. - * @param set usage state of this {@link Entry}. - * @param tag tag of this {@link Entry}. - * @param metered metered state of this {@link Entry}. - * @param roaming roaming state of this {@link Entry}. - * @param defaultNetwork default network status of this {@link Entry}. - * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param rxPackets Number of packets received for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param operations count of network operations performed for this {@link Entry}. This can - * be used to derive bytes-per-operation. - */ - public Entry(@Nullable String iface, int uid, @State int set, int tag, - @Meteredness int metered, @Roaming int roaming, @DefaultNetwork int defaultNetwork, - long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this.iface = iface; - this.uid = uid; - this.set = set; - this.tag = tag; - this.metered = metered; - this.roaming = roaming; - this.defaultNetwork = defaultNetwork; - this.rxBytes = rxBytes; - this.rxPackets = rxPackets; - this.txBytes = txBytes; - this.txPackets = txPackets; - this.operations = operations; - } - - /** @hide */ - public boolean isNegative() { - return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0; - } - - /** @hide */ - public boolean isEmpty() { - return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0 - && operations == 0; - } - - /** @hide */ - public void add(Entry another) { - this.rxBytes += another.rxBytes; - this.rxPackets += another.rxPackets; - this.txBytes += another.txBytes; - this.txPackets += another.txPackets; - this.operations += another.operations; - } - - /** - * @return interface name of this entry. - * @hide - */ - @Nullable public String getIface() { - return iface; - } - - /** - * @return the uid of this entry. - */ - public int getUid() { - return uid; - } - - /** - * @return the set state of this entry. - */ - @State public int getSet() { - return set; - } - - /** - * @return the tag value of this entry. - */ - public int getTag() { - return tag; - } - - /** - * @return the metered state. - */ - @Meteredness public int getMetered() { - return metered; - } - - /** - * @return the roaming state. - */ - @Roaming public int getRoaming() { - return roaming; - } - - /** - * @return the default network state. - */ - @DefaultNetwork public int getDefaultNetwork() { - return defaultNetwork; - } - - /** - * @return the number of received bytes. - */ - public long getRxBytes() { - return rxBytes; - } - - /** - * @return the number of received packets. - */ - public long getRxPackets() { - return rxPackets; - } - - /** - * @return the number of transmitted bytes. - */ - public long getTxBytes() { - return txBytes; - } - - /** - * @return the number of transmitted packets. - */ - public long getTxPackets() { - return txPackets; - } - - /** - * @return the count of network operations performed for this entry. - */ - public long getOperations() { - return operations; - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append("iface=").append(iface); - builder.append(" uid=").append(uid); - builder.append(" set=").append(setToString(set)); - builder.append(" tag=").append(tagToString(tag)); - builder.append(" metered=").append(meteredToString(metered)); - builder.append(" roaming=").append(roamingToString(roaming)); - builder.append(" defaultNetwork=").append(defaultNetworkToString(defaultNetwork)); - builder.append(" rxBytes=").append(rxBytes); - builder.append(" rxPackets=").append(rxPackets); - builder.append(" txBytes=").append(txBytes); - builder.append(" txPackets=").append(txPackets); - builder.append(" operations=").append(operations); - return builder.toString(); - } - - /** @hide */ - @Override - public boolean equals(@Nullable Object o) { - if (o instanceof Entry) { - final Entry e = (Entry) o; - return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered - && roaming == e.roaming && defaultNetwork == e.defaultNetwork - && rxBytes == e.rxBytes && rxPackets == e.rxPackets - && txBytes == e.txBytes && txPackets == e.txPackets - && operations == e.operations && TextUtils.equals(iface, e.iface); - } - return false; - } - - /** @hide */ - @Override - public int hashCode() { - return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface); - } - } - - public NetworkStats(long elapsedRealtime, int initialSize) { - this.elapsedRealtime = elapsedRealtime; - this.size = 0; - if (initialSize > 0) { - this.capacity = initialSize; - this.iface = new String[initialSize]; - this.uid = new int[initialSize]; - this.set = new int[initialSize]; - this.tag = new int[initialSize]; - this.metered = new int[initialSize]; - this.roaming = new int[initialSize]; - this.defaultNetwork = new int[initialSize]; - this.rxBytes = new long[initialSize]; - this.rxPackets = new long[initialSize]; - this.txBytes = new long[initialSize]; - this.txPackets = new long[initialSize]; - this.operations = new long[initialSize]; - } else { - // Special case for use by NetworkStatsFactory to start out *really* empty. - clear(); - } - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public NetworkStats(Parcel parcel) { - elapsedRealtime = parcel.readLong(); - size = parcel.readInt(); - capacity = parcel.readInt(); - iface = parcel.createStringArray(); - uid = parcel.createIntArray(); - set = parcel.createIntArray(); - tag = parcel.createIntArray(); - metered = parcel.createIntArray(); - roaming = parcel.createIntArray(); - defaultNetwork = parcel.createIntArray(); - rxBytes = parcel.createLongArray(); - rxPackets = parcel.createLongArray(); - txBytes = parcel.createLongArray(); - txPackets = parcel.createLongArray(); - operations = parcel.createLongArray(); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeLong(elapsedRealtime); - dest.writeInt(size); - dest.writeInt(capacity); - dest.writeStringArray(iface); - dest.writeIntArray(uid); - dest.writeIntArray(set); - dest.writeIntArray(tag); - dest.writeIntArray(metered); - dest.writeIntArray(roaming); - dest.writeIntArray(defaultNetwork); - dest.writeLongArray(rxBytes); - dest.writeLongArray(rxPackets); - dest.writeLongArray(txBytes); - dest.writeLongArray(txPackets); - dest.writeLongArray(operations); - } - - /** - * @hide - */ - @Override - public NetworkStats clone() { - final NetworkStats clone = new NetworkStats(elapsedRealtime, size); - NetworkStats.Entry entry = null; - for (int i = 0; i < size; i++) { - entry = getValues(i, entry); - clone.insertEntry(entry); - } - return clone; - } - - /** - * Clear all data stored in this object. - * @hide - */ - public void clear() { - this.capacity = 0; - this.iface = EmptyArray.STRING; - this.uid = EmptyArray.INT; - this.set = EmptyArray.INT; - this.tag = EmptyArray.INT; - this.metered = EmptyArray.INT; - this.roaming = EmptyArray.INT; - this.defaultNetwork = EmptyArray.INT; - this.rxBytes = EmptyArray.LONG; - this.rxPackets = EmptyArray.LONG; - this.txBytes = EmptyArray.LONG; - this.txPackets = EmptyArray.LONG; - this.operations = EmptyArray.LONG; - } - - /** @hide */ - @VisibleForTesting - public NetworkStats insertEntry( - String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { - return insertEntry( - iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); - } - - /** @hide */ - @VisibleForTesting - public NetworkStats insertEntry(String iface, int uid, int set, int tag, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { - return insertEntry(new Entry( - iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); - } - - /** @hide */ - @VisibleForTesting - public NetworkStats insertEntry(String iface, int uid, int set, int tag, int metered, - int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, - long txPackets, long operations) { - return insertEntry(new Entry( - iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets, - txBytes, txPackets, operations)); - } - - /** - * Add new stats entry, copying from given {@link Entry}. The {@link Entry} - * object can be recycled across multiple calls. - * @hide - */ - public NetworkStats insertEntry(Entry entry) { - if (size >= capacity) { - final int newLength = Math.max(size, 10) * 3 / 2; - iface = Arrays.copyOf(iface, newLength); - uid = Arrays.copyOf(uid, newLength); - set = Arrays.copyOf(set, newLength); - tag = Arrays.copyOf(tag, newLength); - metered = Arrays.copyOf(metered, newLength); - roaming = Arrays.copyOf(roaming, newLength); - defaultNetwork = Arrays.copyOf(defaultNetwork, newLength); - rxBytes = Arrays.copyOf(rxBytes, newLength); - rxPackets = Arrays.copyOf(rxPackets, newLength); - txBytes = Arrays.copyOf(txBytes, newLength); - txPackets = Arrays.copyOf(txPackets, newLength); - operations = Arrays.copyOf(operations, newLength); - capacity = newLength; - } - - setValues(size, entry); - size++; - - return this; - } - - private void setValues(int i, Entry entry) { - iface[i] = entry.iface; - uid[i] = entry.uid; - set[i] = entry.set; - tag[i] = entry.tag; - metered[i] = entry.metered; - roaming[i] = entry.roaming; - defaultNetwork[i] = entry.defaultNetwork; - rxBytes[i] = entry.rxBytes; - rxPackets[i] = entry.rxPackets; - txBytes[i] = entry.txBytes; - txPackets[i] = entry.txPackets; - operations[i] = entry.operations; - } - - /** - * Iterate over Entry objects. - * - * Return an iterator of this object that will iterate through all contained Entry objects. - * - * This iterator does not support concurrent modification and makes no guarantee of fail-fast - * behavior. If any method that can mutate the contents of this object is called while - * iteration is in progress, either inside the loop or in another thread, then behavior is - * undefined. - * The remove() method is not implemented and will throw UnsupportedOperationException. - * @hide - */ - @SystemApi - @NonNull public Iterator iterator() { - return new Iterator() { - int mIndex = 0; - - @Override - public boolean hasNext() { - return mIndex < size; - } - - @Override - public Entry next() { - return getValues(mIndex++, null); - } - }; - } - - /** - * Return specific stats entry. - * @hide - */ - @UnsupportedAppUsage - public Entry getValues(int i, @Nullable Entry recycle) { - final Entry entry = recycle != null ? recycle : new Entry(); - entry.iface = iface[i]; - entry.uid = uid[i]; - entry.set = set[i]; - entry.tag = tag[i]; - entry.metered = metered[i]; - entry.roaming = roaming[i]; - entry.defaultNetwork = defaultNetwork[i]; - entry.rxBytes = rxBytes[i]; - entry.rxPackets = rxPackets[i]; - entry.txBytes = txBytes[i]; - entry.txPackets = txPackets[i]; - entry.operations = operations[i]; - return entry; - } - - /** - * If @{code dest} is not equal to @{code src}, copy entry from index @{code src} to index - * @{code dest}. - */ - private void maybeCopyEntry(int dest, int src) { - if (dest == src) return; - iface[dest] = iface[src]; - uid[dest] = uid[src]; - set[dest] = set[src]; - tag[dest] = tag[src]; - metered[dest] = metered[src]; - roaming[dest] = roaming[src]; - defaultNetwork[dest] = defaultNetwork[src]; - rxBytes[dest] = rxBytes[src]; - rxPackets[dest] = rxPackets[src]; - txBytes[dest] = txBytes[src]; - txPackets[dest] = txPackets[src]; - operations[dest] = operations[src]; - } - - /** @hide */ - public long getElapsedRealtime() { - return elapsedRealtime; - } - - /** @hide */ - public void setElapsedRealtime(long time) { - elapsedRealtime = time; - } - - /** - * Return age of this {@link NetworkStats} object with respect to - * {@link SystemClock#elapsedRealtime()}. - * @hide - */ - public long getElapsedRealtimeAge() { - return SystemClock.elapsedRealtime() - elapsedRealtime; - } - - /** @hide */ - @UnsupportedAppUsage - public int size() { - return size; - } - - /** @hide */ - @VisibleForTesting - public int internalSize() { - return capacity; - } - - /** @hide */ - @Deprecated - public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets, - long txBytes, long txPackets, long operations) { - return combineValues( - iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, - txPackets, operations); - } - - /** @hide */ - public NetworkStats combineValues(String iface, int uid, int set, int tag, - long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - return combineValues(new Entry( - iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); - } - - /** - * Combine 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. This method mutates the referencing - * {@link NetworkStats} object. - * - * @param entry the {@link Entry} to combine. - * @return a reference to this mutated {@link NetworkStats} object. - * @hide - */ - public @NonNull NetworkStats combineValues(@NonNull Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, - entry.roaming, entry.defaultNetwork); - if (i == -1) { - // only create new entry when positive contribution - insertEntry(entry); - } else { - rxBytes[i] += entry.rxBytes; - rxPackets[i] += entry.rxPackets; - txBytes[i] += entry.txBytes; - txPackets[i] += entry.txPackets; - operations[i] += entry.operations; - } - return this; - } - - /** - * 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. - * - * @param entry the {@link Entry} to add. - * @return a new constructed {@link NetworkStats} object that contains the result. - */ - public @NonNull NetworkStats addEntry(@NonNull Entry entry) { - return this.clone().combineValues(entry); - } - - /** - * Add the given {@link NetworkStats} objects. - * - * @return the sum of two objects. - */ - public @NonNull NetworkStats add(@NonNull NetworkStats another) { - final NetworkStats ret = this.clone(); - ret.combineAllValues(another); - return ret; - } - - /** - * Combine all values from another {@link NetworkStats} into this object. - * @hide - */ - public void combineAllValues(@NonNull NetworkStats another) { - NetworkStats.Entry entry = null; - for (int i = 0; i < another.size; i++) { - entry = another.getValues(i, entry); - combineValues(entry); - } - } - - /** - * Find first stats index that matches the requested parameters. - * @hide - */ - public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming, - int defaultNetwork) { - for (int i = 0; i < size; i++) { - if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && metered == this.metered[i] && roaming == this.roaming[i] - && defaultNetwork == this.defaultNetwork[i] - && Objects.equals(iface, this.iface[i])) { - return i; - } - } - return -1; - } - - /** - * Find first stats index that matches the requested parameters, starting - * search around the hinted index as an optimization. - * @hide - */ - @VisibleForTesting - public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, - int defaultNetwork, int hintIndex) { - for (int offset = 0; offset < size; offset++) { - final int halfOffset = offset / 2; - - // search outwards from hint index, alternating forward and backward - final int i; - if (offset % 2 == 0) { - i = (hintIndex + halfOffset) % size; - } else { - i = (size + hintIndex - halfOffset - 1) % size; - } - - if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && metered == this.metered[i] && roaming == this.roaming[i] - && defaultNetwork == this.defaultNetwork[i] - && Objects.equals(iface, this.iface[i])) { - return i; - } - } - return -1; - } - - /** - * Splice in {@link #operations} from the given {@link NetworkStats} based - * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface}, - * since operation counts are at data layer. - * @hide - */ - public void spliceOperationsFrom(NetworkStats stats) { - for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i], - defaultNetwork[i]); - if (j == -1) { - operations[i] = 0; - } else { - operations[i] = stats.operations[j]; - } - } - } - - /** - * Return list of unique interfaces known by this data structure. - * @hide - */ - public String[] getUniqueIfaces() { - final HashSet ifaces = new HashSet(); - for (String iface : this.iface) { - if (iface != IFACE_ALL) { - ifaces.add(iface); - } - } - return ifaces.toArray(new String[ifaces.size()]); - } - - /** - * Return list of unique UIDs known by this data structure. - * @hide - */ - @UnsupportedAppUsage - public int[] getUniqueUids() { - final SparseBooleanArray uids = new SparseBooleanArray(); - for (int uid : this.uid) { - uids.put(uid, true); - } - - final int size = uids.size(); - final int[] result = new int[size]; - for (int i = 0; i < size; i++) { - result[i] = uids.keyAt(i); - } - return result; - } - - /** - * Return total bytes represented by this snapshot object, usually used when - * checking if a {@link #subtract(NetworkStats)} delta passes a threshold. - * @hide - */ - @UnsupportedAppUsage - public long getTotalBytes() { - final Entry entry = getTotal(null); - return entry.rxBytes + entry.txBytes; - } - - /** - * Return total of all fields represented by this snapshot object. - * @hide - */ - @UnsupportedAppUsage - public Entry getTotal(Entry recycle) { - return getTotal(recycle, null, UID_ALL, false); - } - - /** - * Return total of all fields represented by this snapshot object matching - * the requested {@link #uid}. - * @hide - */ - @UnsupportedAppUsage - public Entry getTotal(Entry recycle, int limitUid) { - return getTotal(recycle, null, limitUid, false); - } - - /** - * Return total of all fields represented by this snapshot object matching - * the requested {@link #iface}. - * @hide - */ - public Entry getTotal(Entry recycle, HashSet limitIface) { - return getTotal(recycle, limitIface, UID_ALL, false); - } - - /** @hide */ - @UnsupportedAppUsage - public Entry getTotalIncludingTags(Entry recycle) { - return getTotal(recycle, null, UID_ALL, true); - } - - /** - * Return total of all fields represented by this snapshot object matching - * the requested {@link #iface} and {@link #uid}. - * - * @param limitIface Set of {@link #iface} to include in total; or {@code - * null} to include all ifaces. - */ - private Entry getTotal( - Entry recycle, HashSet limitIface, int limitUid, boolean includeTags) { - final Entry entry = recycle != null ? recycle : new Entry(); - - entry.iface = IFACE_ALL; - entry.uid = limitUid; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - entry.metered = METERED_ALL; - entry.roaming = ROAMING_ALL; - entry.defaultNetwork = DEFAULT_NETWORK_ALL; - entry.rxBytes = 0; - entry.rxPackets = 0; - entry.txBytes = 0; - entry.txPackets = 0; - entry.operations = 0; - - for (int i = 0; i < size; i++) { - final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]); - final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i])); - - if (matchesUid && matchesIface) { - // skip specific tags, since already counted in TAG_NONE - if (tag[i] != TAG_NONE && !includeTags) continue; - - entry.rxBytes += rxBytes[i]; - entry.rxPackets += rxPackets[i]; - entry.txBytes += txBytes[i]; - entry.txPackets += txPackets[i]; - entry.operations += operations[i]; - } - } - return entry; - } - - /** - * Fast path for battery stats. - * @hide - */ - public long getTotalPackets() { - long total = 0; - for (int i = size-1; i >= 0; i--) { - total += rxPackets[i] + txPackets[i]; - } - return total; - } - - /** - * Subtract the given {@link NetworkStats}, effectively leaving the delta - * between two snapshots in time. Assumes that statistics rows collect over - * time, and that none of them have disappeared. This method does not mutate - * the referencing object. - * - * @return the delta between two objects. - */ - public @NonNull NetworkStats subtract(@NonNull NetworkStats right) { - return subtract(this, right, null, null); - } - - /** - * Subtract the two given {@link NetworkStats} objects, returning the delta - * between two snapshots in time. Assumes that statistics rows collect over - * time, and that none of them have disappeared. - *

- * If counters have rolled backwards, they are clamped to {@code 0} and - * reported to the given {@link NonMonotonicObserver}. - * @hide - */ - public static NetworkStats subtract(NetworkStats left, NetworkStats right, - NonMonotonicObserver observer, C cookie) { - return subtract(left, right, observer, cookie, null); - } - - /** - * Subtract the two given {@link NetworkStats} objects, returning the delta - * between two snapshots in time. Assumes that statistics rows collect over - * time, and that none of them have disappeared. - *

- * If counters have rolled backwards, they are clamped to {@code 0} and - * reported to the given {@link NonMonotonicObserver}. - *

- * If recycle is supplied, this NetworkStats object will be - * reused (and returned) as the result if it is large enough to contain - * the data. - * @hide - */ - public static NetworkStats subtract(NetworkStats left, NetworkStats right, - NonMonotonicObserver observer, C cookie, NetworkStats recycle) { - long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime; - if (deltaRealtime < 0) { - if (observer != null) { - observer.foundNonMonotonic(left, -1, right, -1, cookie); - } - deltaRealtime = 0; - } - - // result will have our rows, and elapsed time between snapshots - final Entry entry = new Entry(); - final NetworkStats result; - if (recycle != null && recycle.capacity >= left.size) { - result = recycle; - result.size = 0; - result.elapsedRealtime = deltaRealtime; - } else { - result = new NetworkStats(deltaRealtime, left.size); - } - for (int i = 0; i < left.size; i++) { - entry.iface = left.iface[i]; - entry.uid = left.uid[i]; - entry.set = left.set[i]; - entry.tag = left.tag[i]; - entry.metered = left.metered[i]; - entry.roaming = left.roaming[i]; - entry.defaultNetwork = left.defaultNetwork[i]; - entry.rxBytes = left.rxBytes[i]; - entry.rxPackets = left.rxPackets[i]; - entry.txBytes = left.txBytes[i]; - entry.txPackets = left.txPackets[i]; - entry.operations = left.operations[i]; - - // find remote row that matches, and subtract - final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, - entry.metered, entry.roaming, entry.defaultNetwork, i); - if (j != -1) { - // Found matching row, subtract remote value. - entry.rxBytes -= right.rxBytes[j]; - entry.rxPackets -= right.rxPackets[j]; - entry.txBytes -= right.txBytes[j]; - entry.txPackets -= right.txPackets[j]; - entry.operations -= right.operations[j]; - } - - if (entry.isNegative()) { - if (observer != null) { - observer.foundNonMonotonic(left, i, right, j, cookie); - } - entry.rxBytes = Math.max(entry.rxBytes, 0); - entry.rxPackets = Math.max(entry.rxPackets, 0); - entry.txBytes = Math.max(entry.txBytes, 0); - entry.txPackets = Math.max(entry.txPackets, 0); - entry.operations = Math.max(entry.operations, 0); - } - - result.insertEntry(entry); - } - - return result; - } - - /** - * Calculate and apply adjustments to captured statistics for 464xlat traffic. - * - *

This mutates stacked traffic stats, to account for IPv4/IPv6 header size difference. - * - *

UID stats, which are only accounted on the stacked interface, need to be increased - * by 20 bytes/packet to account for translation overhead. - * - *

The potential additional overhead of 8 bytes/packet for ip fragments is ignored. - * - *

Interface stats need to sum traffic on both stacked and base interface because: - * - eBPF offloaded packets appear only on the stacked interface - * - Non-offloaded ingress packets appear only on the stacked interface - * (due to iptables raw PREROUTING drop rules) - * - Non-offloaded egress packets appear only on the stacked interface - * (due to ignoring traffic from clat daemon by uid match) - * (and of course the 20 bytes/packet overhead needs to be applied to stacked interface stats) - * - *

This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only - * {@code ConcurrentHashMap} - * @param baseTraffic Traffic on the base interfaces. Will be mutated. - * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. - * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. - * @hide - */ - public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, Map stackedIfaces) { - // For recycling - Entry entry = null; - for (int i = 0; i < stackedTraffic.size; i++) { - entry = stackedTraffic.getValues(i, entry); - if (entry == null) continue; - if (entry.iface == null) continue; - if (!entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) continue; - - // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet - // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after - // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes - // difference for all packets (http://b/12249687, http:/b/33681750). - // - // Note: this doesn't account for LRO/GRO/GSO/TSO (ie. >mtu) traffic correctly, nor - // does it correctly account for the 8 extra bytes in the IPv6 fragmentation header. - // - // While the ebpf code path does try to simulate proper post segmentation packet - // counts, we have nothing of the sort of xt_qtaguid stats. - entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; - entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; - stackedTraffic.setValues(i, entry); - } - } - - /** - * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. - * - *

This mutates the object this method is called on. Equivalent to calling - * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as - * base and stacked traffic. - * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. - * @hide - */ - public void apply464xlatAdjustments(Map stackedIfaces) { - apply464xlatAdjustments(this, this, stackedIfaces); - } - - /** - * Return total statistics grouped by {@link #iface}; doesn't mutate the - * original structure. - * @hide - */ - public NetworkStats groupedByIface() { - final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); - - final Entry entry = new Entry(); - entry.uid = UID_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - entry.metered = METERED_ALL; - entry.roaming = ROAMING_ALL; - entry.defaultNetwork = DEFAULT_NETWORK_ALL; - entry.operations = 0L; - - for (int i = 0; i < size; i++) { - // skip specific tags, since already counted in TAG_NONE - if (tag[i] != TAG_NONE) continue; - - entry.iface = iface[i]; - entry.rxBytes = rxBytes[i]; - entry.rxPackets = rxPackets[i]; - entry.txBytes = txBytes[i]; - entry.txPackets = txPackets[i]; - stats.combineValues(entry); - } - - return stats; - } - - /** - * Return total statistics grouped by {@link #uid}; doesn't mutate the - * original structure. - * @hide - */ - public NetworkStats groupedByUid() { - final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); - - final Entry entry = new Entry(); - entry.iface = IFACE_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - entry.metered = METERED_ALL; - entry.roaming = ROAMING_ALL; - entry.defaultNetwork = DEFAULT_NETWORK_ALL; - - for (int i = 0; i < size; i++) { - // skip specific tags, since already counted in TAG_NONE - if (tag[i] != TAG_NONE) continue; - - entry.uid = uid[i]; - entry.rxBytes = rxBytes[i]; - entry.rxPackets = rxPackets[i]; - entry.txBytes = txBytes[i]; - entry.txPackets = txPackets[i]; - entry.operations = operations[i]; - stats.combineValues(entry); - } - - return stats; - } - - /** - * Remove all rows that match one of specified UIDs. - * This mutates the original structure in place. - * @hide - */ - public void removeUids(int[] uids) { - filter(e -> !CollectionUtils.contains(uids, e.uid)); - } - - /** - * Remove all rows that match one of specified UIDs. - * @return the result object. - * @hide - */ - @NonNull - public NetworkStats removeEmptyEntries() { - final NetworkStats ret = this.clone(); - ret.filter(e -> e.rxBytes != 0 || e.rxPackets != 0 || e.txBytes != 0 || e.txPackets != 0 - || e.operations != 0); - return ret; - } - - /** - * Only keep entries that match all specified filters. - * - *

This mutates the original structure in place. After this method is called, - * size is the number of matching entries, and capacity is the previous capacity. - * @param limitUid UID to filter for, or {@link #UID_ALL}. - * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}. - * @param limitTag Tag to filter for, or {@link #TAG_ALL}. - * @hide - */ - public void filter(int limitUid, String[] limitIfaces, int limitTag) { - if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { - return; - } - filter(e -> (limitUid == UID_ALL || limitUid == e.uid) - && (limitTag == TAG_ALL || limitTag == e.tag) - && (limitIfaces == INTERFACES_ALL - || CollectionUtils.contains(limitIfaces, e.iface))); - } - - /** - * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. - * - *

This mutates the original structure in place. - * @hide - */ - public void filterDebugEntries() { - filter(e -> e.set < SET_DEBUG_START); - } - - private void filter(Predicate predicate) { - Entry entry = new Entry(); - int nextOutputEntry = 0; - for (int i = 0; i < size; i++) { - entry = getValues(i, entry); - if (predicate.test(entry)) { - if (nextOutputEntry != i) { - setValues(nextOutputEntry, entry); - } - nextOutputEntry++; - } - } - size = nextOutputEntry; - } - - /** @hide */ - public void dump(String prefix, PrintWriter pw) { - pw.print(prefix); - pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); - for (int i = 0; i < size; i++) { - pw.print(prefix); - pw.print(" ["); pw.print(i); pw.print("]"); - pw.print(" iface="); pw.print(iface[i]); - pw.print(" uid="); pw.print(uid[i]); - pw.print(" set="); pw.print(setToString(set[i])); - pw.print(" tag="); pw.print(tagToString(tag[i])); - pw.print(" metered="); pw.print(meteredToString(metered[i])); - pw.print(" roaming="); pw.print(roamingToString(roaming[i])); - pw.print(" defaultNetwork="); pw.print(defaultNetworkToString(defaultNetwork[i])); - pw.print(" rxBytes="); pw.print(rxBytes[i]); - pw.print(" rxPackets="); pw.print(rxPackets[i]); - pw.print(" txBytes="); pw.print(txBytes[i]); - pw.print(" txPackets="); pw.print(txPackets[i]); - pw.print(" operations="); pw.println(operations[i]); - } - } - - /** - * Return text description of {@link #set} value. - * @hide - */ - public static String setToString(int set) { - switch (set) { - case SET_ALL: - return "ALL"; - case SET_DEFAULT: - return "DEFAULT"; - case SET_FOREGROUND: - return "FOREGROUND"; - case SET_DBG_VPN_IN: - return "DBG_VPN_IN"; - case SET_DBG_VPN_OUT: - return "DBG_VPN_OUT"; - default: - return "UNKNOWN"; - } - } - - /** - * Return text description of {@link #set} value. - * @hide - */ - public static String setToCheckinString(int set) { - switch (set) { - case SET_ALL: - return "all"; - case SET_DEFAULT: - return "def"; - case SET_FOREGROUND: - return "fg"; - case SET_DBG_VPN_IN: - return "vpnin"; - case SET_DBG_VPN_OUT: - return "vpnout"; - default: - return "unk"; - } - } - - /** - * @return true if the querySet matches the dataSet. - * @hide - */ - public static boolean setMatches(int querySet, int dataSet) { - if (querySet == dataSet) { - return true; - } - // SET_ALL matches all non-debugging sets. - return querySet == SET_ALL && dataSet < SET_DEBUG_START; - } - - /** - * Return text description of {@link #tag} value. - * @hide - */ - public static String tagToString(int tag) { - return "0x" + Integer.toHexString(tag); - } - - /** - * Return text description of {@link #metered} value. - * @hide - */ - public static String meteredToString(int metered) { - switch (metered) { - case METERED_ALL: - return "ALL"; - case METERED_NO: - return "NO"; - case METERED_YES: - return "YES"; - default: - return "UNKNOWN"; - } - } - - /** - * Return text description of {@link #roaming} value. - * @hide - */ - public static String roamingToString(int roaming) { - switch (roaming) { - case ROAMING_ALL: - return "ALL"; - case ROAMING_NO: - return "NO"; - case ROAMING_YES: - return "YES"; - default: - return "UNKNOWN"; - } - } - - /** - * Return text description of {@link #defaultNetwork} value. - * @hide - */ - public static String defaultNetworkToString(int defaultNetwork) { - switch (defaultNetwork) { - case DEFAULT_NETWORK_ALL: - return "ALL"; - case DEFAULT_NETWORK_NO: - return "NO"; - case DEFAULT_NETWORK_YES: - return "YES"; - default: - return "UNKNOWN"; - } - } - - /** @hide */ - @Override - public String toString() { - final CharArrayWriter writer = new CharArrayWriter(); - dump("", new PrintWriter(writer)); - return writer.toString(); - } - - @Override - public int describeContents() { - return 0; - } - - public static final @NonNull Creator CREATOR = new Creator() { - @Override - public NetworkStats createFromParcel(Parcel in) { - return new NetworkStats(in); - } - - @Override - public NetworkStats[] newArray(int size) { - return new NetworkStats[size]; - } - }; - - /** @hide */ - public interface NonMonotonicObserver { - public void foundNonMonotonic( - NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie); - public void foundNonMonotonic( - NetworkStats stats, int statsIndex, C cookie); - } - - /** - * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface. - * - *

This method should only be called on delta NetworkStats. Do not call this method on a - * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may change - * over time. - * - *

This method performs adjustments for one active VPN package and one VPN iface at a time. - * - * @param tunUid uid of the VPN application - * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application - * @hide - */ - public void migrateTun(int tunUid, @NonNull String tunIface, - @NonNull List underlyingIfaces) { - // Combined usage by all apps using VPN. - final Entry tunIfaceTotal = new Entry(); - // Usage by VPN, grouped by its {@code underlyingIfaces}. - final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.size()]; - // Usage by VPN, summed across all its {@code underlyingIfaces}. - final Entry underlyingIfacesTotal = new Entry(); - - for (int i = 0; i < perInterfaceTotal.length; i++) { - perInterfaceTotal[i] = new Entry(); - } - - tunAdjustmentInit(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, perInterfaceTotal, - underlyingIfacesTotal); - - // If tunIface < underlyingIfacesTotal, it leaves the overhead traffic in the VPN app. - // If tunIface > underlyingIfacesTotal, the VPN app doesn't get credit for data compression. - // Negative stats should be avoided. - final Entry[] moved = - addTrafficToApplications(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, - perInterfaceTotal, underlyingIfacesTotal); - deductTrafficFromVpnApp(tunUid, underlyingIfaces, moved); - } - - /** - * Initializes the data used by the migrateTun() method. - * - *

This is the first pass iteration which does the following work: - * - *

    - *
  • Adds up all the traffic through the tunUid's underlyingIfaces (both foreground and - * background). - *
  • Adds up all the traffic through tun0 excluding traffic from the vpn app itself. - *
- * - * @param tunUid uid of the VPN application - * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application - * @param tunIfaceTotal output parameter; combined data usage by all apps using VPN - * @param perInterfaceTotal output parameter; data usage by VPN app, grouped by its {@code - * underlyingIfaces} - * @param underlyingIfacesTotal output parameter; data usage by VPN, summed across all of its - * {@code underlyingIfaces} - */ - private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, - @NonNull List underlyingIfaces, @NonNull Entry tunIfaceTotal, - @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { - final Entry recycle = new Entry(); - for (int i = 0; i < size; i++) { - getValues(i, recycle); - if (recycle.uid == UID_ALL) { - throw new IllegalStateException( - "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); - } - if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { - throw new IllegalStateException( - "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*"); - } - if (recycle.tag != TAG_NONE) { - // TODO(b/123666283): Take all tags for tunUid into account. - continue; - } - - if (tunUid == Process.SYSTEM_UID) { - // Kernel-based VPN or VCN, traffic sent by apps on the VPN/VCN network - // - // Since the data is not UID-accounted on underlying networks, just use VPN/VCN - // network usage as ground truth. Encrypted traffic on the underlying networks will - // never be processed here because encrypted traffic on the underlying interfaces - // is not present in UID stats, and this method is only called on UID stats. - if (tunIface.equals(recycle.iface)) { - tunIfaceTotal.add(recycle); - underlyingIfacesTotal.add(recycle); - - // In steady state, there should always be one network, but edge cases may - // result in the network being null (network lost), and thus no underlying - // ifaces is possible. - if (perInterfaceTotal.length > 0) { - // While platform VPNs and VCNs have exactly one underlying network, that - // network may have multiple interfaces (eg for 464xlat). This layer does - // not have the required information to identify which of the interfaces - // were used. Select "any" of the interfaces. Since overhead is already - // lost, this number is an approximation anyways. - perInterfaceTotal[0].add(recycle); - } - } - } else if (recycle.uid == tunUid) { - // VpnService VPN, traffic sent by the VPN app over underlying networks - for (int j = 0; j < underlyingIfaces.size(); j++) { - if (Objects.equals(underlyingIfaces.get(j), recycle.iface)) { - perInterfaceTotal[j].add(recycle); - underlyingIfacesTotal.add(recycle); - break; - } - } - } else if (tunIface.equals(recycle.iface)) { - // VpnService VPN; traffic sent by apps on the VPN network - tunIfaceTotal.add(recycle); - } - } - } - - /** - * Distributes traffic across apps that are using given {@code tunIface}, and returns the total - * traffic that should be moved off of {@code tunUid} grouped by {@code underlyingIfaces}. - * - * @param tunUid uid of the VPN application - * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application - * @param tunIfaceTotal combined data usage across all apps using {@code tunIface} - * @param perInterfaceTotal data usage by VPN app, grouped by its {@code underlyingIfaces} - * @param underlyingIfacesTotal data usage by VPN, summed across all of its {@code - * underlyingIfaces} - */ - private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, - @NonNull List underlyingIfaces, @NonNull Entry tunIfaceTotal, - @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { - // Traffic that should be moved off of each underlying interface for tunUid (see - // deductTrafficFromVpnApp below). - final Entry[] moved = new Entry[underlyingIfaces.size()]; - for (int i = 0; i < underlyingIfaces.size(); i++) { - moved[i] = new Entry(); - } - - final Entry tmpEntry = new Entry(); - final int origSize = size; - for (int i = 0; i < origSize; i++) { - if (!Objects.equals(iface[i], tunIface)) { - // Consider only entries that go onto the VPN interface. - continue; - } - - if (uid[i] == tunUid && tunUid != Process.SYSTEM_UID) { - // Exclude VPN app from the redistribution, as it can choose to create packet - // streams by writing to itself. - // - // However, for platform VPNs, do not exclude the system's usage of the VPN network, - // since it is never local-only, and never double counted - continue; - } - tmpEntry.uid = uid[i]; - tmpEntry.tag = tag[i]; - tmpEntry.metered = metered[i]; - tmpEntry.roaming = roaming[i]; - tmpEntry.defaultNetwork = defaultNetwork[i]; - - // In a first pass, compute this entry's total share of data across all - // underlyingIfaces. This is computed on the basis of the share of this entry's usage - // over tunIface. - // TODO: Consider refactoring first pass into a separate helper method. - long totalRxBytes = 0; - if (tunIfaceTotal.rxBytes > 0) { - // Note - The multiplication below should not overflow since NetworkStatsService - // processes this every time device has transmitted/received amount equivalent to - // global threshold alert (~ 2MB) across all interfaces. - final long rxBytesAcrossUnderlyingIfaces = - multiplySafeByRational(underlyingIfacesTotal.rxBytes, - rxBytes[i], tunIfaceTotal.rxBytes); - // app must not be blamed for more than it consumed on tunIface - totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces); - } - long totalRxPackets = 0; - if (tunIfaceTotal.rxPackets > 0) { - final long rxPacketsAcrossUnderlyingIfaces = - multiplySafeByRational(underlyingIfacesTotal.rxPackets, - rxPackets[i], tunIfaceTotal.rxPackets); - totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces); - } - long totalTxBytes = 0; - if (tunIfaceTotal.txBytes > 0) { - final long txBytesAcrossUnderlyingIfaces = - multiplySafeByRational(underlyingIfacesTotal.txBytes, - txBytes[i], tunIfaceTotal.txBytes); - totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces); - } - long totalTxPackets = 0; - if (tunIfaceTotal.txPackets > 0) { - final long txPacketsAcrossUnderlyingIfaces = - multiplySafeByRational(underlyingIfacesTotal.txPackets, - txPackets[i], tunIfaceTotal.txPackets); - totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces); - } - long totalOperations = 0; - if (tunIfaceTotal.operations > 0) { - final long operationsAcrossUnderlyingIfaces = - multiplySafeByRational(underlyingIfacesTotal.operations, - operations[i], tunIfaceTotal.operations); - totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces); - } - // In a second pass, distribute these values across interfaces in the proportion that - // each interface represents of the total traffic of the underlying interfaces. - for (int j = 0; j < underlyingIfaces.size(); j++) { - tmpEntry.iface = underlyingIfaces.get(j); - tmpEntry.rxBytes = 0; - // Reset 'set' to correct value since it gets updated when adding debug info below. - tmpEntry.set = set[i]; - if (underlyingIfacesTotal.rxBytes > 0) { - tmpEntry.rxBytes = - multiplySafeByRational(totalRxBytes, - perInterfaceTotal[j].rxBytes, - underlyingIfacesTotal.rxBytes); - } - tmpEntry.rxPackets = 0; - if (underlyingIfacesTotal.rxPackets > 0) { - tmpEntry.rxPackets = - multiplySafeByRational(totalRxPackets, - perInterfaceTotal[j].rxPackets, - underlyingIfacesTotal.rxPackets); - } - tmpEntry.txBytes = 0; - if (underlyingIfacesTotal.txBytes > 0) { - tmpEntry.txBytes = - multiplySafeByRational(totalTxBytes, - perInterfaceTotal[j].txBytes, - underlyingIfacesTotal.txBytes); - } - tmpEntry.txPackets = 0; - if (underlyingIfacesTotal.txPackets > 0) { - tmpEntry.txPackets = - multiplySafeByRational(totalTxPackets, - perInterfaceTotal[j].txPackets, - underlyingIfacesTotal.txPackets); - } - tmpEntry.operations = 0; - if (underlyingIfacesTotal.operations > 0) { - tmpEntry.operations = - multiplySafeByRational(totalOperations, - perInterfaceTotal[j].operations, - underlyingIfacesTotal.operations); - } - // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying - // interface. Add that data usage to this object. - combineValues(tmpEntry); - if (tag[i] == TAG_NONE) { - // Add the migrated data to moved so it is deducted from the VPN app later. - moved[j].add(tmpEntry); - // Add debug info - tmpEntry.set = SET_DBG_VPN_IN; - combineValues(tmpEntry); - } - } - } - return moved; - } - - private void deductTrafficFromVpnApp( - int tunUid, - @NonNull List underlyingIfaces, - @NonNull Entry[] moved) { - if (tunUid == Process.SYSTEM_UID) { - // No traffic recorded on a per-UID basis for in-kernel VPN/VCNs over underlying - // networks; thus no traffic to deduct. - return; - } - - for (int i = 0; i < underlyingIfaces.size(); i++) { - moved[i].uid = tunUid; - // Add debug info - moved[i].set = SET_DBG_VPN_OUT; - moved[i].tag = TAG_NONE; - moved[i].iface = underlyingIfaces.get(i); - moved[i].metered = METERED_ALL; - moved[i].roaming = ROAMING_ALL; - moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; - combineValues(moved[i]); - - // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than - // the TAG_NONE traffic. - // - // Relies on the fact that the underlying traffic only has state ROAMING_NO and - // METERED_NO, which should be the case as it comes directly from the /proc file. - // We only blend in the roaming data after applying these adjustments, by checking the - // NetworkIdentity of the underlying iface. - final int idxVpnBackground = findIndex(underlyingIfaces.get(i), tunUid, SET_DEFAULT, - TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnBackground != -1) { - // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed - // from foreground usage. - tunSubtract(idxVpnBackground, this, moved[i]); - } - - final int idxVpnForeground = findIndex(underlyingIfaces.get(i), tunUid, SET_FOREGROUND, - TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnForeground != -1) { - tunSubtract(idxVpnForeground, this, moved[i]); - } - } - } - - private static void tunSubtract(int i, @NonNull NetworkStats left, @NonNull Entry right) { - long rxBytes = Math.min(left.rxBytes[i], right.rxBytes); - left.rxBytes[i] -= rxBytes; - right.rxBytes -= rxBytes; - - long rxPackets = Math.min(left.rxPackets[i], right.rxPackets); - left.rxPackets[i] -= rxPackets; - right.rxPackets -= rxPackets; - - long txBytes = Math.min(left.txBytes[i], right.txBytes); - left.txBytes[i] -= txBytes; - right.txBytes -= txBytes; - - long txPackets = Math.min(left.txPackets[i], right.txPackets); - left.txPackets[i] -= txPackets; - right.txPackets -= txPackets; - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java deleted file mode 100644 index b64fbdba9a01f..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsAccess.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (C) 2015 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; - -import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.NetworkStats.UID_ALL; -import static android.net.TrafficStats.UID_REMOVED; -import static android.net.TrafficStats.UID_TETHERING; - -import android.Manifest; -import android.annotation.IntDef; -import android.app.AppOpsManager; -import android.app.admin.DevicePolicyManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.Process; -import android.os.UserHandle; -import android.telephony.TelephonyManager; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Utility methods for controlling access to network stats APIs. - * - * @hide - */ -public final class NetworkStatsAccess { - private NetworkStatsAccess() {} - - /** - * Represents an access level for the network usage history and statistics APIs. - * - *

Access levels are in increasing order; that is, it is reasonable to check access by - * verifying that the caller's access level is at least the minimum required level. - */ - @IntDef({ - Level.DEFAULT, - Level.USER, - Level.DEVICESUMMARY, - Level.DEVICE, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Level { - /** - * Default, unprivileged access level. - * - *

Can only access usage for one's own UID. - * - *

Every app will have at least this access level. - */ - int DEFAULT = 0; - - /** - * Access level for apps which can access usage for any app running in the same user. - * - *

Granted to: - *

    - *
  • Profile owners. - *
- */ - int USER = 1; - - /** - * Access level for apps which can access usage summary of device. Device summary includes - * usage by apps running in any profiles/users, however this access level does not - * allow querying usage of individual apps running in other profiles/users. - * - *

Granted to: - *

    - *
  • Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit - * so it is not necessarily sufficient to declare this in the manifest. - *
  • Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission. - *
- */ - int DEVICESUMMARY = 2; - - /** - * Access level for apps which can access usage for any app on the device, including apps - * running on other users/profiles. - * - *

Granted to: - *

    - *
  • Device owners. - *
  • Carrier-privileged applications. - *
  • The system UID. - *
- */ - int DEVICE = 3; - } - - /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */ - public static @NetworkStatsAccess.Level int checkAccessLevel( - Context context, int callingPid, int callingUid, String callingPackage) { - final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class); - final TelephonyManager tm = (TelephonyManager) - context.getSystemService(Context.TELEPHONY_SERVICE); - boolean hasCarrierPrivileges; - final long token = Binder.clearCallingIdentity(); - try { - hasCarrierPrivileges = tm != null - && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) - == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; - } finally { - Binder.restoreCallingIdentity(token); - } - - final boolean isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage); - final int appId = UserHandle.getAppId(callingUid); - - final boolean isNetworkStack = context.checkPermission( - android.Manifest.permission.NETWORK_STACK, callingPid, callingUid) - == PERMISSION_GRANTED; - - if (hasCarrierPrivileges || isDeviceOwner - || appId == Process.SYSTEM_UID || isNetworkStack) { - // Carrier-privileged apps and device owners, and the system (including the - // network stack) can access data usage for all apps on the device. - return NetworkStatsAccess.Level.DEVICE; - } - - boolean hasAppOpsPermission = hasAppOpsPermission(context, callingUid, callingPackage); - if (hasAppOpsPermission || context.checkCallingOrSelfPermission( - READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) { - return NetworkStatsAccess.Level.DEVICESUMMARY; - } - - //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. - boolean isProfileOwner = mDpm != null && (mDpm.isProfileOwnerApp(callingPackage) - || mDpm.isDeviceOwnerApp(callingPackage)); - if (isProfileOwner) { - // Apps with the AppOps permission, profile owners, and apps with the privileged - // permission can access data usage for all apps in this user/profile. - return NetworkStatsAccess.Level.USER; - } - - // Everyone else gets default access (only to their own UID). - return NetworkStatsAccess.Level.DEFAULT; - } - - /** - * Returns whether the given caller should be able to access the given UID when the caller has - * the given {@link NetworkStatsAccess.Level}. - */ - public static boolean isAccessibleToUser(int uid, int callerUid, - @NetworkStatsAccess.Level int accessLevel) { - final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier(); - final int callerUserId = UserHandle.getUserHandleForUid(callerUid).getIdentifier(); - switch (accessLevel) { - case NetworkStatsAccess.Level.DEVICE: - // Device-level access - can access usage for any uid. - return true; - case NetworkStatsAccess.Level.DEVICESUMMARY: - // Can access usage for any app running in the same user, along - // with some special uids (system, removed, or tethering) and - // anonymized uids - return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED - || uid == UID_TETHERING || uid == UID_ALL - || userId == callerUserId; - case NetworkStatsAccess.Level.USER: - // User-level access - can access usage for any app running in the same user, along - // with some special uids (system, removed, or tethering). - return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED - || uid == UID_TETHERING - || userId == callerUserId; - case NetworkStatsAccess.Level.DEFAULT: - default: - // Default access level - can only access one's own usage. - return uid == callerUid; - } - } - - private static boolean hasAppOpsPermission( - Context context, int callingUid, String callingPackage) { - if (callingPackage != null) { - AppOpsManager appOps = (AppOpsManager) context.getSystemService( - Context.APP_OPS_SERVICE); - - final int mode = appOps.noteOp(AppOpsManager.OPSTR_GET_USAGE_STATS, - callingUid, callingPackage, null /* attributionTag */, null /* message */); - if (mode == AppOpsManager.MODE_DEFAULT) { - // The default behavior here is to check if PackageManager has given the app - // permission. - final int permissionCheck = context.checkCallingPermission( - Manifest.permission.PACKAGE_USAGE_STATS); - return permissionCheck == PackageManager.PERMISSION_GRANTED; - } - return (mode == AppOpsManager.MODE_ALLOWED); - } - return false; - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java deleted file mode 100644 index e385b33447f01..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java +++ /dev/null @@ -1,956 +0,0 @@ -/* - * Copyright (C) 2012 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; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.NetworkStats.DEFAULT_NETWORK_NO; -import static android.net.NetworkStats.DEFAULT_NETWORK_YES; -import static android.net.NetworkStats.IFACE_ALL; -import static android.net.NetworkStats.METERED_NO; -import static android.net.NetworkStats.METERED_YES; -import static android.net.NetworkStats.ROAMING_NO; -import static android.net.NetworkStats.ROAMING_YES; -import static android.net.NetworkStats.SET_ALL; -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; -import static android.net.TrafficStats.UID_REMOVED; -import static android.text.format.DateUtils.WEEK_IN_MILLIS; - -import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.net.NetworkStats.State; -import android.net.NetworkStatsHistory.Entry; -import android.os.Binder; -import android.service.NetworkStatsCollectionKeyProto; -import android.service.NetworkStatsCollectionProto; -import android.service.NetworkStatsCollectionStatsProto; -import android.telephony.SubscriptionPlan; -import android.text.format.DateUtils; -import android.util.ArrayMap; -import android.util.AtomicFile; -import android.util.IndentingPrintWriter; -import android.util.Log; -import android.util.Range; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.FileRotator; -import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.NetworkStatsUtils; - -import libcore.io.IoUtils; - -import java.io.BufferedInputStream; -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.DataOutput; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.net.ProtocolException; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -/** - * Collection of {@link NetworkStatsHistory}, stored based on combined key of - * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself. - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.Writer { - private static final String TAG = NetworkStatsCollection.class.getSimpleName(); - /** File header magic number: "ANET" */ - private static final int FILE_MAGIC = 0x414E4554; - - private static final int VERSION_NETWORK_INIT = 1; - - private static final int VERSION_UID_INIT = 1; - private static final int VERSION_UID_WITH_IDENT = 2; - private static final int VERSION_UID_WITH_TAG = 3; - private static final int VERSION_UID_WITH_SET = 4; - - private static final int VERSION_UNIFIED_INIT = 16; - - private ArrayMap mStats = new ArrayMap<>(); - - private final long mBucketDurationMillis; - - private long mStartMillis; - private long mEndMillis; - private long mTotalBytes; - private boolean mDirty; - - /** - * Construct a {@link NetworkStatsCollection} object. - * - * @param bucketDuration duration of the buckets in this object, in milliseconds. - * @hide - */ - public NetworkStatsCollection(long bucketDurationMillis) { - mBucketDurationMillis = bucketDurationMillis; - reset(); - } - - /** @hide */ - public void clear() { - reset(); - } - - /** @hide */ - public void reset() { - mStats.clear(); - mStartMillis = Long.MAX_VALUE; - mEndMillis = Long.MIN_VALUE; - mTotalBytes = 0; - mDirty = false; - } - - /** @hide */ - public long getStartMillis() { - return mStartMillis; - } - - /** - * Return first atomic bucket in this collection, which is more conservative - * than {@link #mStartMillis}. - * @hide - */ - public long getFirstAtomicBucketMillis() { - if (mStartMillis == Long.MAX_VALUE) { - return Long.MAX_VALUE; - } else { - return mStartMillis + mBucketDurationMillis; - } - } - - /** @hide */ - public long getEndMillis() { - return mEndMillis; - } - - /** @hide */ - public long getTotalBytes() { - return mTotalBytes; - } - - /** @hide */ - public boolean isDirty() { - return mDirty; - } - - /** @hide */ - public void clearDirty() { - mDirty = false; - } - - /** @hide */ - public boolean isEmpty() { - return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE; - } - - /** @hide */ - @VisibleForTesting - public long roundUp(long time) { - if (time == Long.MIN_VALUE || time == Long.MAX_VALUE - || time == SubscriptionPlan.TIME_UNKNOWN) { - return time; - } else { - final long mod = time % mBucketDurationMillis; - if (mod > 0) { - time -= mod; - time += mBucketDurationMillis; - } - return time; - } - } - - /** @hide */ - @VisibleForTesting - public long roundDown(long time) { - if (time == Long.MIN_VALUE || time == Long.MAX_VALUE - || time == SubscriptionPlan.TIME_UNKNOWN) { - return time; - } else { - final long mod = time % mBucketDurationMillis; - if (mod > 0) { - time -= mod; - } - return time; - } - } - - /** @hide */ - public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { - return getRelevantUids(accessLevel, Binder.getCallingUid()); - } - - /** @hide */ - public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel, - final int callerUid) { - final ArrayList uids = new ArrayList<>(); - for (int i = 0; i < mStats.size(); i++) { - final Key key = mStats.keyAt(i); - if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) { - int j = Collections.binarySearch(uids, new Integer(key.uid)); - - if (j < 0) { - j = ~j; - uids.add(j, key.uid); - } - } - } - return CollectionUtils.toIntArray(uids); - } - - /** - * Combine all {@link NetworkStatsHistory} in this collection which match - * the requested parameters. - * @hide - */ - public NetworkStatsHistory getHistory(NetworkTemplate template, SubscriptionPlan augmentPlan, - int uid, int set, int tag, int fields, long start, long end, - @NetworkStatsAccess.Level int accessLevel, int callerUid) { - if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) { - throw new SecurityException("Network stats history of uid " + uid - + " is forbidden for caller " + callerUid); - } - - // 180 days of history should be enough for anyone; if we end up needing - // more, we'll dynamically grow the history object. - final int bucketEstimate = (int) NetworkStatsUtils.constrain( - ((end - start) / mBucketDurationMillis), 0, - (180 * DateUtils.DAY_IN_MILLIS) / mBucketDurationMillis); - final NetworkStatsHistory combined = new NetworkStatsHistory( - mBucketDurationMillis, bucketEstimate, fields); - - // shortcut when we know stats will be empty - if (start == end) return combined; - - // Figure out the window of time that we should be augmenting (if any) - long augmentStart = SubscriptionPlan.TIME_UNKNOWN; - long augmentEnd = (augmentPlan != null) ? augmentPlan.getDataUsageTime() - : SubscriptionPlan.TIME_UNKNOWN; - // And if augmenting, we might need to collect more data to adjust with - long collectStart = start; - long collectEnd = end; - - if (augmentEnd != SubscriptionPlan.TIME_UNKNOWN) { - final Iterator> it = augmentPlan.cycleIterator(); - while (it.hasNext()) { - final Range cycle = it.next(); - final long cycleStart = cycle.getLower().toInstant().toEpochMilli(); - final long cycleEnd = cycle.getUpper().toInstant().toEpochMilli(); - if (cycleStart <= augmentEnd && augmentEnd < cycleEnd) { - augmentStart = cycleStart; - collectStart = Long.min(collectStart, augmentStart); - collectEnd = Long.max(collectEnd, augmentEnd); - break; - } - } - } - - if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) { - // Shrink augmentation window so we don't risk undercounting. - augmentStart = roundUp(augmentStart); - augmentEnd = roundDown(augmentEnd); - // Grow collection window so we get all the stats needed. - collectStart = roundDown(collectStart); - collectEnd = roundUp(collectEnd); - } - - for (int i = 0; i < mStats.size(); i++) { - final Key key = mStats.keyAt(i); - if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag - && templateMatches(template, key.ident)) { - final NetworkStatsHistory value = mStats.valueAt(i); - combined.recordHistory(value, collectStart, collectEnd); - } - } - - if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) { - final NetworkStatsHistory.Entry entry = combined.getValues( - augmentStart, augmentEnd, null); - - // If we don't have any recorded data for this time period, give - // ourselves something to scale with. - if (entry.rxBytes == 0 || entry.txBytes == 0) { - combined.recordData(augmentStart, augmentEnd, - new NetworkStats.Entry(1, 0, 1, 0, 0)); - combined.getValues(augmentStart, augmentEnd, entry); - } - - final long rawBytes = (entry.rxBytes + entry.txBytes) == 0 ? 1 : - (entry.rxBytes + entry.txBytes); - final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes; - final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes; - final long targetBytes = augmentPlan.getDataUsageBytes(); - - final long targetRxBytes = multiplySafeByRational(targetBytes, rawRxBytes, rawBytes); - final long targetTxBytes = multiplySafeByRational(targetBytes, rawTxBytes, rawBytes); - - - // Scale all matching buckets to reach anchor target - final long beforeTotal = combined.getTotalBytes(); - for (int i = 0; i < combined.size(); i++) { - combined.getValues(i, entry); - if (entry.bucketStart >= augmentStart - && entry.bucketStart + entry.bucketDuration <= augmentEnd) { - entry.rxBytes = multiplySafeByRational( - targetRxBytes, entry.rxBytes, rawRxBytes); - entry.txBytes = multiplySafeByRational( - targetTxBytes, entry.txBytes, rawTxBytes); - // We purposefully clear out packet counters to indicate - // that this data has been augmented. - entry.rxPackets = 0; - entry.txPackets = 0; - combined.setValues(i, entry); - } - } - - final long deltaTotal = combined.getTotalBytes() - beforeTotal; - if (deltaTotal != 0) { - Log.d(TAG, "Augmented network usage by " + deltaTotal + " bytes"); - } - - // Finally we can slice data as originally requested - final NetworkStatsHistory sliced = new NetworkStatsHistory( - mBucketDurationMillis, bucketEstimate, fields); - sliced.recordHistory(combined, start, end); - return sliced; - } else { - return combined; - } - } - - /** - * Summarize all {@link NetworkStatsHistory} in this collection which match - * the requested parameters across the requested range. - * - * @param template - a predicate for filtering netstats. - * @param start - start of the range, timestamp in milliseconds since the epoch. - * @param end - end of the range, timestamp in milliseconds since the epoch. - * @param accessLevel - caller access level. - * @param callerUid - caller UID. - * @hide - */ - public NetworkStats getSummary(NetworkTemplate template, long start, long end, - @NetworkStatsAccess.Level int accessLevel, int callerUid) { - final long now = System.currentTimeMillis(); - - final NetworkStats stats = new NetworkStats(end - start, 24); - - // shortcut when we know stats will be empty - if (start == end) return stats; - - final NetworkStats.Entry entry = new NetworkStats.Entry(); - NetworkStatsHistory.Entry historyEntry = null; - - for (int i = 0; i < mStats.size(); i++) { - final Key key = mStats.keyAt(i); - if (templateMatches(template, key.ident) - && NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel) - && key.set < NetworkStats.SET_DEBUG_START) { - final NetworkStatsHistory value = mStats.valueAt(i); - historyEntry = value.getValues(start, end, now, historyEntry); - - entry.iface = IFACE_ALL; - entry.uid = key.uid; - entry.set = key.set; - entry.tag = key.tag; - entry.defaultNetwork = key.ident.areAllMembersOnDefaultNetwork() - ? DEFAULT_NETWORK_YES : DEFAULT_NETWORK_NO; - entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; - entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; - entry.rxBytes = historyEntry.rxBytes; - entry.rxPackets = historyEntry.rxPackets; - entry.txBytes = historyEntry.txBytes; - entry.txPackets = historyEntry.txPackets; - entry.operations = historyEntry.operations; - - if (!entry.isEmpty()) { - stats.combineValues(entry); - } - } - } - - return stats; - } - - /** - * Record given {@link android.net.NetworkStats.Entry} into this collection. - * @hide - */ - public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start, - long end, NetworkStats.Entry entry) { - final NetworkStatsHistory history = findOrCreateHistory(ident, uid, set, tag); - history.recordData(start, end, entry); - noteRecordedHistory(history.getStart(), history.getEnd(), entry.rxBytes + entry.txBytes); - } - - /** - * Record given {@link NetworkStatsHistory} into this collection. - * - * @hide - */ - public void recordHistory(@NonNull Key key, @NonNull NetworkStatsHistory history) { - Objects.requireNonNull(key); - Objects.requireNonNull(history); - if (history.size() == 0) return; - noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes()); - - NetworkStatsHistory target = mStats.get(key); - if (target == null) { - target = new NetworkStatsHistory(history.getBucketDuration()); - mStats.put(key, target); - } - target.recordEntireHistory(history); - } - - /** - * Record all {@link NetworkStatsHistory} contained in the given collection - * into this collection. - * - * @hide - */ - public void recordCollection(@NonNull NetworkStatsCollection another) { - Objects.requireNonNull(another); - for (int i = 0; i < another.mStats.size(); i++) { - final Key key = another.mStats.keyAt(i); - final NetworkStatsHistory value = another.mStats.valueAt(i); - recordHistory(key, value); - } - } - - private NetworkStatsHistory findOrCreateHistory( - NetworkIdentitySet ident, int uid, int set, int tag) { - final Key key = new Key(ident, uid, set, tag); - final NetworkStatsHistory existing = mStats.get(key); - - // update when no existing, or when bucket duration changed - NetworkStatsHistory updated = null; - if (existing == null) { - updated = new NetworkStatsHistory(mBucketDurationMillis, 10); - } else if (existing.getBucketDuration() != mBucketDurationMillis) { - updated = new NetworkStatsHistory(existing, mBucketDurationMillis); - } - - if (updated != null) { - mStats.put(key, updated); - return updated; - } else { - return existing; - } - } - - /** @hide */ - @Override - public void read(InputStream in) throws IOException { - read((DataInput) new DataInputStream(in)); - } - - private void read(DataInput in) throws IOException { - // verify file magic header intact - final int magic = in.readInt(); - if (magic != FILE_MAGIC) { - throw new ProtocolException("unexpected magic: " + magic); - } - - final int version = in.readInt(); - switch (version) { - case VERSION_UNIFIED_INIT: { - // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) - final int identSize = in.readInt(); - for (int i = 0; i < identSize; i++) { - final NetworkIdentitySet ident = new NetworkIdentitySet(in); - - final int size = in.readInt(); - for (int j = 0; j < size; j++) { - final int uid = in.readInt(); - final int set = in.readInt(); - final int tag = in.readInt(); - - final Key key = new Key(ident, uid, set, tag); - final NetworkStatsHistory history = new NetworkStatsHistory(in); - recordHistory(key, history); - } - } - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - } - - /** @hide */ - @Override - public void write(OutputStream out) throws IOException { - write((DataOutput) new DataOutputStream(out)); - out.flush(); - } - - private void write(DataOutput out) throws IOException { - // cluster key lists grouped by ident - final HashMap> keysByIdent = new HashMap<>(); - for (Key key : mStats.keySet()) { - ArrayList keys = keysByIdent.get(key.ident); - if (keys == null) { - keys = new ArrayList<>(); - keysByIdent.put(key.ident, keys); - } - keys.add(key); - } - - out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_UNIFIED_INIT); - - out.writeInt(keysByIdent.size()); - for (NetworkIdentitySet ident : keysByIdent.keySet()) { - final ArrayList keys = keysByIdent.get(ident); - ident.writeToStream(out); - - out.writeInt(keys.size()); - for (Key key : keys) { - final NetworkStatsHistory history = mStats.get(key); - out.writeInt(key.uid); - out.writeInt(key.set); - out.writeInt(key.tag); - history.writeToStream(out); - } - } - } - - /** - * Read legacy network summary statistics file format into the collection, - * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}. - * - * @deprecated - * @hide - */ - @Deprecated - public void readLegacyNetwork(File file) throws IOException { - final AtomicFile inputFile = new AtomicFile(file); - - DataInputStream in = null; - try { - in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); - - // verify file magic header intact - final int magic = in.readInt(); - if (magic != FILE_MAGIC) { - throw new ProtocolException("unexpected magic: " + magic); - } - - final int version = in.readInt(); - switch (version) { - case VERSION_NETWORK_INIT: { - // network := size *(NetworkIdentitySet NetworkStatsHistory) - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - final NetworkIdentitySet ident = new NetworkIdentitySet(in); - final NetworkStatsHistory history = new NetworkStatsHistory(in); - - final Key key = new Key(ident, UID_ALL, SET_ALL, TAG_NONE); - recordHistory(key, history); - } - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - } catch (FileNotFoundException e) { - // missing stats is okay, probably first boot - } finally { - IoUtils.closeQuietly(in); - } - } - - /** - * Read legacy Uid statistics file format into the collection, - * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}. - * - * @deprecated - * @hide - */ - @Deprecated - public void readLegacyUid(File file, boolean onlyTags) throws IOException { - final AtomicFile inputFile = new AtomicFile(file); - - DataInputStream in = null; - try { - in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); - - // verify file magic header intact - final int magic = in.readInt(); - if (magic != FILE_MAGIC) { - throw new ProtocolException("unexpected magic: " + magic); - } - - final int version = in.readInt(); - switch (version) { - case VERSION_UID_INIT: { - // uid := size *(UID NetworkStatsHistory) - - // drop this data version, since we don't have a good - // mapping into NetworkIdentitySet. - break; - } - case VERSION_UID_WITH_IDENT: { - // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) - - // drop this data version, since this version only existed - // for a short time. - break; - } - case VERSION_UID_WITH_TAG: - case VERSION_UID_WITH_SET: { - // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) - final int identSize = in.readInt(); - for (int i = 0; i < identSize; i++) { - final NetworkIdentitySet ident = new NetworkIdentitySet(in); - - final int size = in.readInt(); - for (int j = 0; j < size; j++) { - final int uid = in.readInt(); - final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt() - : SET_DEFAULT; - final int tag = in.readInt(); - - final Key key = new Key(ident, uid, set, tag); - final NetworkStatsHistory history = new NetworkStatsHistory(in); - - if ((tag == TAG_NONE) != onlyTags) { - recordHistory(key, history); - } - } - } - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - } catch (FileNotFoundException e) { - // missing stats is okay, probably first boot - } finally { - IoUtils.closeQuietly(in); - } - } - - /** - * Remove any {@link NetworkStatsHistory} attributed to the requested UID, - * moving any {@link NetworkStats#TAG_NONE} series to - * {@link TrafficStats#UID_REMOVED}. - * @hide - */ - public void removeUids(int[] uids) { - final ArrayList knownKeys = new ArrayList<>(); - knownKeys.addAll(mStats.keySet()); - - // migrate all UID stats into special "removed" bucket - for (Key key : knownKeys) { - if (CollectionUtils.contains(uids, key.uid)) { - // only migrate combined TAG_NONE history - if (key.tag == TAG_NONE) { - final NetworkStatsHistory uidHistory = mStats.get(key); - final NetworkStatsHistory removedHistory = findOrCreateHistory( - key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE); - removedHistory.recordEntireHistory(uidHistory); - } - mStats.remove(key); - mDirty = true; - } - } - } - - private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) { - if (startMillis < mStartMillis) mStartMillis = startMillis; - if (endMillis > mEndMillis) mEndMillis = endMillis; - mTotalBytes += totalBytes; - mDirty = true; - } - - private int estimateBuckets() { - return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5) - / mBucketDurationMillis); - } - - private ArrayList getSortedKeys() { - final ArrayList keys = new ArrayList<>(); - keys.addAll(mStats.keySet()); - Collections.sort(keys, (left, right) -> Key.compare(left, right)); - return keys; - } - - /** @hide */ - public void dump(IndentingPrintWriter pw) { - for (Key key : getSortedKeys()) { - pw.print("ident="); pw.print(key.ident.toString()); - pw.print(" uid="); pw.print(key.uid); - pw.print(" set="); pw.print(NetworkStats.setToString(key.set)); - pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag)); - - final NetworkStatsHistory history = mStats.get(key); - pw.increaseIndent(); - history.dump(pw, true); - pw.decreaseIndent(); - } - } - - /** @hide */ - public void dumpDebug(ProtoOutputStream proto, long tag) { - final long start = proto.start(tag); - - for (Key key : getSortedKeys()) { - final long startStats = proto.start(NetworkStatsCollectionProto.STATS); - - // Key - final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); - key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY); - proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); - proto.write(NetworkStatsCollectionKeyProto.SET, key.set); - proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); - proto.end(startKey); - - // Value - final NetworkStatsHistory history = mStats.get(key); - history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY); - proto.end(startStats); - } - - proto.end(start); - } - - /** @hide */ - public void dumpCheckin(PrintWriter pw, long start, long end) { - dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell"); - dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi"); - dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateEthernet(), "eth"); - dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateBluetooth(), "bt"); - } - - /** - * Dump all contained stats that match requested parameters, but group - * together all matching {@link NetworkTemplate} under a single prefix. - */ - private void dumpCheckin(PrintWriter pw, long start, long end, NetworkTemplate groupTemplate, - String groupPrefix) { - final ArrayMap grouped = new ArrayMap<>(); - - // Walk through all history, grouping by matching network templates - for (int i = 0; i < mStats.size(); i++) { - final Key key = mStats.keyAt(i); - final NetworkStatsHistory value = mStats.valueAt(i); - - if (!templateMatches(groupTemplate, key.ident)) continue; - if (key.set >= NetworkStats.SET_DEBUG_START) continue; - - final Key groupKey = new Key(null, key.uid, key.set, key.tag); - NetworkStatsHistory groupHistory = grouped.get(groupKey); - if (groupHistory == null) { - groupHistory = new NetworkStatsHistory(value.getBucketDuration()); - grouped.put(groupKey, groupHistory); - } - groupHistory.recordHistory(value, start, end); - } - - for (int i = 0; i < grouped.size(); i++) { - final Key key = grouped.keyAt(i); - final NetworkStatsHistory value = grouped.valueAt(i); - - if (value.size() == 0) continue; - - pw.print("c,"); - pw.print(groupPrefix); pw.print(','); - pw.print(key.uid); pw.print(','); - pw.print(NetworkStats.setToCheckinString(key.set)); pw.print(','); - pw.print(key.tag); - pw.println(); - - value.dumpCheckin(pw); - } - } - - /** - * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} - * in the given {@link NetworkIdentitySet}. - */ - private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) { - for (NetworkIdentity ident : identSet) { - if (template.matches(ident)) { - return true; - } - } - return false; - } - - /** - * Get the all historical stats of the collection {@link NetworkStatsCollection}. - * - * @return All {@link NetworkStatsHistory} in this collection. - */ - @NonNull - public Map getEntries() { - return new ArrayMap(mStats); - } - - /** - * Builder class for {@link NetworkStatsCollection}. - */ - public static final class Builder { - private final long mBucketDurationMillis; - private final ArrayMap mEntries = new ArrayMap<>(); - - /** - * Creates a new Builder with given bucket duration. - * - * @param bucketDuration Duration of the buckets of the object, in milliseconds. - */ - public Builder(long bucketDurationMillis) { - mBucketDurationMillis = bucketDurationMillis; - } - - /** - * Add association of the history with the specified key in this map. - * - * @param key The object used to identify a network, see {@link Key}. - * @param history {@link NetworkStatsHistory} instance associated to the given {@link Key}. - * @return The builder object. - */ - @NonNull - public NetworkStatsCollection.Builder addEntry(@NonNull Key key, - @NonNull NetworkStatsHistory history) { - Objects.requireNonNull(key); - Objects.requireNonNull(history); - final List historyEntries = history.getEntries(); - - final NetworkStatsHistory.Builder historyBuilder = - new NetworkStatsHistory.Builder(mBucketDurationMillis, historyEntries.size()); - for (Entry entry : historyEntries) { - historyBuilder.addEntry(entry); - } - - mEntries.put(key, historyBuilder.build()); - return this; - } - - /** - * Builds the instance of the {@link NetworkStatsCollection}. - * - * @return the built instance of {@link NetworkStatsCollection}. - */ - @NonNull - public NetworkStatsCollection build() { - final NetworkStatsCollection collection = - new NetworkStatsCollection(mBucketDurationMillis); - for (int i = 0; i < mEntries.size(); i++) { - collection.recordHistory(mEntries.keyAt(i), mEntries.valueAt(i)); - } - return collection; - } - } - - /** - * the identifier that associate with the {@link NetworkStatsHistory} object to identify - * a certain record in the {@link NetworkStatsCollection} object. - */ - public static final class Key { - /** @hide */ - public final NetworkIdentitySet ident; - /** @hide */ - public final int uid; - /** @hide */ - public final int set; - /** @hide */ - public final int tag; - - private final int mHashCode; - - /** - * Construct a {@link Key} object. - * - * @param ident a Set of {@link NetworkIdentity} that associated with the record. - * @param uid Uid of the record. - * @param set Set of the record, see {@code NetworkStats#SET_*}. - * @param tag Tag of the record, see {@link TrafficStats#setThreadStatsTag(int)}. - */ - public Key(@NonNull Set ident, int uid, @State int set, int tag) { - this(new NetworkIdentitySet(Objects.requireNonNull(ident)), uid, set, tag); - } - - /** @hide */ - public Key(@NonNull NetworkIdentitySet ident, int uid, int set, int tag) { - this.ident = Objects.requireNonNull(ident); - this.uid = uid; - this.set = set; - this.tag = tag; - mHashCode = Objects.hash(ident, uid, set, tag); - } - - @Override - public int hashCode() { - return mHashCode; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof Key) { - final Key key = (Key) obj; - return uid == key.uid && set == key.set && tag == key.tag - && Objects.equals(ident, key.ident); - } - return false; - } - - /** @hide */ - public static int compare(@NonNull Key left, @NonNull Key right) { - Objects.requireNonNull(left); - Objects.requireNonNull(right); - int res = 0; - if (left.ident != null && right.ident != null) { - res = NetworkIdentitySet.compare(left.ident, right.ident); - } - if (res == 0) { - res = Integer.compare(left.uid, right.uid); - } - if (res == 0) { - res = Integer.compare(left.set, right.set); - } - if (res == 0) { - res = Integer.compare(left.tag, right.tag); - } - return res; - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.aidl b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.aidl deleted file mode 100644 index 8b9069f8fa488..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2011, 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; - -parcelable NetworkStatsHistory; diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java deleted file mode 100644 index 301fef9441692..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsHistory.java +++ /dev/null @@ -1,1162 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.NetworkStats.IFACE_ALL; -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray; -import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray; -import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray; -import static android.net.NetworkStatsHistory.Entry.UNKNOWN; -import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; -import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; -import static android.text.format.DateUtils.SECOND_IN_MILLIS; - -import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.service.NetworkStatsHistoryBucketProto; -import android.service.NetworkStatsHistoryProto; -import android.util.IndentingPrintWriter; -import android.util.proto.ProtoOutputStream; - -import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.NetworkStatsUtils; - -import libcore.util.EmptyArray; - -import java.io.CharArrayWriter; -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.ProtocolException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - -/** - * Collection of historical network statistics, recorded into equally-sized - * "buckets" in time. Internally it stores data in {@code long} series for more - * efficient persistence. - *

- * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for - * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is - * sorted at all times. - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public final class NetworkStatsHistory implements Parcelable { - private static final int VERSION_INIT = 1; - private static final int VERSION_ADD_PACKETS = 2; - private static final int VERSION_ADD_ACTIVE = 3; - - /** @hide */ - public static final int FIELD_ACTIVE_TIME = 0x01; - /** @hide */ - public static final int FIELD_RX_BYTES = 0x02; - /** @hide */ - public static final int FIELD_RX_PACKETS = 0x04; - /** @hide */ - public static final int FIELD_TX_BYTES = 0x08; - /** @hide */ - public static final int FIELD_TX_PACKETS = 0x10; - /** @hide */ - public static final int FIELD_OPERATIONS = 0x20; - /** @hide */ - public static final int FIELD_ALL = 0xFFFFFFFF; - - private long bucketDuration; - private int bucketCount; - private long[] bucketStart; - private long[] activeTime; - private long[] rxBytes; - private long[] rxPackets; - private long[] txBytes; - private long[] txPackets; - private long[] operations; - private long totalBytes; - - /** @hide */ - public NetworkStatsHistory(long bucketDuration, long[] bucketStart, long[] activeTime, - long[] rxBytes, long[] rxPackets, long[] txBytes, long[] txPackets, - long[] operations, int bucketCount, long totalBytes) { - this.bucketDuration = bucketDuration; - this.bucketStart = bucketStart; - this.activeTime = activeTime; - this.rxBytes = rxBytes; - this.rxPackets = rxPackets; - this.txBytes = txBytes; - this.txPackets = txPackets; - this.operations = operations; - this.bucketCount = bucketCount; - this.totalBytes = totalBytes; - } - - /** - * An instance to represent a single record in a {@link NetworkStatsHistory} object. - */ - public static final class Entry { - /** @hide */ - public static final long UNKNOWN = -1; - - /** @hide */ - // TODO: Migrate all callers to get duration from the history object and remove this field. - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long bucketDuration; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long bucketStart; - /** @hide */ - public long activeTime; - /** @hide */ - @UnsupportedAppUsage - public long rxBytes; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long rxPackets; - /** @hide */ - @UnsupportedAppUsage - public long txBytes; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public long txPackets; - /** @hide */ - public long operations; - /** @hide */ - Entry() {} - - /** - * Construct a {@link Entry} instance to represent a single record in a - * {@link NetworkStatsHistory} object. - * - * @param bucketStart Start of period for this {@link Entry}, in milliseconds since the - * Unix epoch, see {@link java.lang.System#currentTimeMillis}. - * @param activeTime Active time for this {@link Entry}, in milliseconds. - * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param rxPackets Number of packets received for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should - * represent the contents of IP packets, including IP headers. - * @param operations count of network operations performed for this {@link Entry}. This can - * be used to derive bytes-per-operation. - */ - public Entry(long bucketStart, long activeTime, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { - this.bucketStart = bucketStart; - this.activeTime = activeTime; - this.rxBytes = rxBytes; - this.rxPackets = rxPackets; - this.txBytes = txBytes; - this.txPackets = txPackets; - this.operations = operations; - } - - /** - * Get start timestamp of the bucket's time interval, in milliseconds since the Unix epoch. - */ - public long getBucketStart() { - return bucketStart; - } - - /** - * Get active time of the bucket's time interval, in milliseconds. - */ - public long getActiveTime() { - return activeTime; - } - - /** Get number of bytes received for this {@link Entry}. */ - public long getRxBytes() { - return rxBytes; - } - - /** Get number of packets received for this {@link Entry}. */ - public long getRxPackets() { - return rxPackets; - } - - /** Get number of bytes transmitted for this {@link Entry}. */ - public long getTxBytes() { - return txBytes; - } - - /** Get number of packets transmitted for this {@link Entry}. */ - public long getTxPackets() { - return txPackets; - } - - /** Get count of network operations performed for this {@link Entry}. */ - public long getOperations() { - return operations; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o.getClass() != getClass()) return false; - Entry entry = (Entry) o; - return bucketStart == entry.bucketStart - && activeTime == entry.activeTime && rxBytes == entry.rxBytes - && rxPackets == entry.rxPackets && txBytes == entry.txBytes - && txPackets == entry.txPackets && operations == entry.operations; - } - - @Override - public int hashCode() { - return (int) (bucketStart * 2 - + activeTime * 3 - + rxBytes * 5 - + rxPackets * 7 - + txBytes * 11 - + txPackets * 13 - + operations * 17); - } - - @Override - public String toString() { - return "Entry{" - + "bucketStart=" + bucketStart - + ", activeTime=" + activeTime - + ", rxBytes=" + rxBytes - + ", rxPackets=" + rxPackets - + ", txBytes=" + txBytes - + ", txPackets=" + txPackets - + ", operations=" + operations - + "}"; - } - } - - /** @hide */ - @UnsupportedAppUsage - public NetworkStatsHistory(long bucketDuration) { - this(bucketDuration, 10, FIELD_ALL); - } - - /** @hide */ - public NetworkStatsHistory(long bucketDuration, int initialSize) { - this(bucketDuration, initialSize, FIELD_ALL); - } - - /** @hide */ - public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) { - this.bucketDuration = bucketDuration; - bucketStart = new long[initialSize]; - if ((fields & FIELD_ACTIVE_TIME) != 0) activeTime = new long[initialSize]; - if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize]; - if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize]; - if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize]; - if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize]; - if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize]; - bucketCount = 0; - totalBytes = 0; - } - - /** @hide */ - public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) { - this(bucketDuration, existing.estimateResizeBuckets(bucketDuration)); - recordEntireHistory(existing); - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public NetworkStatsHistory(Parcel in) { - bucketDuration = in.readLong(); - bucketStart = readLongArray(in); - activeTime = readLongArray(in); - rxBytes = readLongArray(in); - rxPackets = readLongArray(in); - txBytes = readLongArray(in); - txPackets = readLongArray(in); - operations = readLongArray(in); - bucketCount = bucketStart.length; - totalBytes = in.readLong(); - } - - @Override - public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeLong(bucketDuration); - writeLongArray(out, bucketStart, bucketCount); - writeLongArray(out, activeTime, bucketCount); - writeLongArray(out, rxBytes, bucketCount); - writeLongArray(out, rxPackets, bucketCount); - writeLongArray(out, txBytes, bucketCount); - writeLongArray(out, txPackets, bucketCount); - writeLongArray(out, operations, bucketCount); - out.writeLong(totalBytes); - } - - /** @hide */ - public NetworkStatsHistory(DataInput in) throws IOException { - final int version = in.readInt(); - switch (version) { - case VERSION_INIT: { - bucketDuration = in.readLong(); - bucketStart = readFullLongArray(in); - rxBytes = readFullLongArray(in); - rxPackets = new long[bucketStart.length]; - txBytes = readFullLongArray(in); - txPackets = new long[bucketStart.length]; - operations = new long[bucketStart.length]; - bucketCount = bucketStart.length; - totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes); - break; - } - case VERSION_ADD_PACKETS: - case VERSION_ADD_ACTIVE: { - bucketDuration = in.readLong(); - bucketStart = readVarLongArray(in); - activeTime = (version >= VERSION_ADD_ACTIVE) ? readVarLongArray(in) - : new long[bucketStart.length]; - rxBytes = readVarLongArray(in); - rxPackets = readVarLongArray(in); - txBytes = readVarLongArray(in); - txPackets = readVarLongArray(in); - operations = readVarLongArray(in); - bucketCount = bucketStart.length; - totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes); - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - - if (bucketStart.length != bucketCount || rxBytes.length != bucketCount - || rxPackets.length != bucketCount || txBytes.length != bucketCount - || txPackets.length != bucketCount || operations.length != bucketCount) { - throw new ProtocolException("Mismatched history lengths"); - } - } - - /** @hide */ - public void writeToStream(DataOutput out) throws IOException { - out.writeInt(VERSION_ADD_ACTIVE); - out.writeLong(bucketDuration); - writeVarLongArray(out, bucketStart, bucketCount); - writeVarLongArray(out, activeTime, bucketCount); - writeVarLongArray(out, rxBytes, bucketCount); - writeVarLongArray(out, rxPackets, bucketCount); - writeVarLongArray(out, txBytes, bucketCount); - writeVarLongArray(out, txPackets, bucketCount); - writeVarLongArray(out, operations, bucketCount); - } - - @Override - public int describeContents() { - return 0; - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int size() { - return bucketCount; - } - - /** @hide */ - public long getBucketDuration() { - return bucketDuration; - } - - /** @hide */ - @UnsupportedAppUsage - public long getStart() { - if (bucketCount > 0) { - return bucketStart[0]; - } else { - return Long.MAX_VALUE; - } - } - - /** @hide */ - @UnsupportedAppUsage - public long getEnd() { - if (bucketCount > 0) { - return bucketStart[bucketCount - 1] + bucketDuration; - } else { - return Long.MIN_VALUE; - } - } - - /** - * Return total bytes represented by this history. - * @hide - */ - public long getTotalBytes() { - return totalBytes; - } - - /** - * Return index of bucket that contains or is immediately before the - * requested time. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int getIndexBefore(long time) { - int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); - if (index < 0) { - index = (~index) - 1; - } else { - index -= 1; - } - return NetworkStatsUtils.constrain(index, 0, bucketCount - 1); - } - - /** - * Return index of bucket that contains or is immediately after the - * requested time. - * @hide - */ - public int getIndexAfter(long time) { - int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); - if (index < 0) { - index = ~index; - } else { - index += 1; - } - return NetworkStatsUtils.constrain(index, 0, bucketCount - 1); - } - - /** - * Return specific stats entry. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public Entry getValues(int i, Entry recycle) { - final Entry entry = recycle != null ? recycle : new Entry(); - entry.bucketStart = bucketStart[i]; - entry.bucketDuration = bucketDuration; - entry.activeTime = getLong(activeTime, i, UNKNOWN); - entry.rxBytes = getLong(rxBytes, i, UNKNOWN); - entry.rxPackets = getLong(rxPackets, i, UNKNOWN); - entry.txBytes = getLong(txBytes, i, UNKNOWN); - entry.txPackets = getLong(txPackets, i, UNKNOWN); - entry.operations = getLong(operations, i, UNKNOWN); - return entry; - } - - /** - * Get List of {@link Entry} of the {@link NetworkStatsHistory} instance. - * - * @return - */ - @NonNull - public List getEntries() { - // TODO: Return a wrapper that uses this list instead, to prevent the returned result - // from being changed. - final ArrayList ret = new ArrayList<>(size()); - for (int i = 0; i < size(); i++) { - ret.add(getValues(i, null /* recycle */)); - } - return ret; - } - - /** @hide */ - public void setValues(int i, Entry entry) { - // Unwind old values - if (rxBytes != null) totalBytes -= rxBytes[i]; - if (txBytes != null) totalBytes -= txBytes[i]; - - bucketStart[i] = entry.bucketStart; - setLong(activeTime, i, entry.activeTime); - setLong(rxBytes, i, entry.rxBytes); - setLong(rxPackets, i, entry.rxPackets); - setLong(txBytes, i, entry.txBytes); - setLong(txPackets, i, entry.txPackets); - setLong(operations, i, entry.operations); - - // Apply new values - if (rxBytes != null) totalBytes += rxBytes[i]; - if (txBytes != null) totalBytes += txBytes[i]; - } - - /** - * Record that data traffic occurred in the given time range. Will - * distribute across internal buckets, creating new buckets as needed. - * @hide - */ - @Deprecated - public void recordData(long start, long end, long rxBytes, long txBytes) { - recordData(start, end, new NetworkStats.Entry( - IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L)); - } - - /** - * Record that data traffic occurred in the given time range. Will - * distribute across internal buckets, creating new buckets as needed. - * @hide - */ - public void recordData(long start, long end, NetworkStats.Entry entry) { - long rxBytes = entry.rxBytes; - long rxPackets = entry.rxPackets; - long txBytes = entry.txBytes; - long txPackets = entry.txPackets; - long operations = entry.operations; - - if (entry.isNegative()) { - throw new IllegalArgumentException("tried recording negative data"); - } - if (entry.isEmpty()) { - return; - } - - // create any buckets needed by this range - ensureBuckets(start, end); - // Return fast if there is still no entry. This would typically happen when the start, - // end or duration are not valid values, e.g. start > end, negative duration value, etc. - if (bucketCount == 0) return; - - // distribute data usage into buckets - long duration = end - start; - final int startIndex = getIndexAfter(end); - for (int i = startIndex; i >= 0; i--) { - final long curStart = bucketStart[i]; - final long curEnd = curStart + bucketDuration; - - // bucket is older than record; we're finished - if (curEnd < start) break; - // bucket is newer than record; keep looking - if (curStart > end) continue; - - final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); - if (overlap <= 0) continue; - - // integer math each time is faster than floating point - final long fracRxBytes = multiplySafeByRational(rxBytes, overlap, duration); - final long fracRxPackets = multiplySafeByRational(rxPackets, overlap, duration); - final long fracTxBytes = multiplySafeByRational(txBytes, overlap, duration); - final long fracTxPackets = multiplySafeByRational(txPackets, overlap, duration); - final long fracOperations = multiplySafeByRational(operations, overlap, duration); - - - addLong(activeTime, i, overlap); - addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes; - addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets; - addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes; - addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets; - addLong(this.operations, i, fracOperations); operations -= fracOperations; - - duration -= overlap; - } - - totalBytes += entry.rxBytes + entry.txBytes; - } - - /** - * Record an entire {@link NetworkStatsHistory} into this history. Usually - * for combining together stats for external reporting. - * @hide - */ - @UnsupportedAppUsage - public void recordEntireHistory(NetworkStatsHistory input) { - recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE); - } - - /** - * Record given {@link NetworkStatsHistory} into this history, copying only - * buckets that atomically occur in the inclusive time range. Doesn't - * interpolate across partial buckets. - * @hide - */ - public void recordHistory(NetworkStatsHistory input, long start, long end) { - final NetworkStats.Entry entry = new NetworkStats.Entry( - IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); - for (int i = 0; i < input.bucketCount; i++) { - final long bucketStart = input.bucketStart[i]; - final long bucketEnd = bucketStart + input.bucketDuration; - - // skip when bucket is outside requested range - if (bucketStart < start || bucketEnd > end) continue; - - entry.rxBytes = getLong(input.rxBytes, i, 0L); - entry.rxPackets = getLong(input.rxPackets, i, 0L); - entry.txBytes = getLong(input.txBytes, i, 0L); - entry.txPackets = getLong(input.txPackets, i, 0L); - entry.operations = getLong(input.operations, i, 0L); - - recordData(bucketStart, bucketEnd, entry); - } - } - - /** - * Ensure that buckets exist for given time range, creating as needed. - */ - private void ensureBuckets(long start, long end) { - // normalize incoming range to bucket boundaries - start -= start % bucketDuration; - end += (bucketDuration - (end % bucketDuration)) % bucketDuration; - - for (long now = start; now < end; now += bucketDuration) { - // try finding existing bucket - final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now); - if (index < 0) { - // bucket missing, create and insert - insertBucket(~index, now); - } - } - } - - /** - * Insert new bucket at requested index and starting time. - */ - private void insertBucket(int index, long start) { - // create more buckets when needed - if (bucketCount >= bucketStart.length) { - final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; - bucketStart = Arrays.copyOf(bucketStart, newLength); - if (activeTime != null) activeTime = Arrays.copyOf(activeTime, newLength); - if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength); - if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength); - if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength); - if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength); - if (operations != null) operations = Arrays.copyOf(operations, newLength); - } - - // create gap when inserting bucket in middle - if (index < bucketCount) { - final int dstPos = index + 1; - final int length = bucketCount - index; - - System.arraycopy(bucketStart, index, bucketStart, dstPos, length); - if (activeTime != null) System.arraycopy(activeTime, index, activeTime, dstPos, length); - if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length); - if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length); - if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length); - if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length); - if (operations != null) System.arraycopy(operations, index, operations, dstPos, length); - } - - bucketStart[index] = start; - setLong(activeTime, index, 0L); - setLong(rxBytes, index, 0L); - setLong(rxPackets, index, 0L); - setLong(txBytes, index, 0L); - setLong(txPackets, index, 0L); - setLong(operations, index, 0L); - bucketCount++; - } - - /** - * Clear all data stored in this object. - * @hide - */ - public void clear() { - bucketStart = EmptyArray.LONG; - if (activeTime != null) activeTime = EmptyArray.LONG; - if (rxBytes != null) rxBytes = EmptyArray.LONG; - if (rxPackets != null) rxPackets = EmptyArray.LONG; - if (txBytes != null) txBytes = EmptyArray.LONG; - if (txPackets != null) txPackets = EmptyArray.LONG; - if (operations != null) operations = EmptyArray.LONG; - bucketCount = 0; - totalBytes = 0; - } - - /** - * Remove buckets older than requested cutoff. - * @hide - */ - public void removeBucketsBefore(long cutoff) { - // TODO: Consider use getIndexBefore. - int i; - for (i = 0; i < bucketCount; i++) { - final long curStart = bucketStart[i]; - final long curEnd = curStart + bucketDuration; - - // cutoff happens before or during this bucket; everything before - // this bucket should be removed. - if (curEnd > cutoff) break; - } - - if (i > 0) { - final int length = bucketStart.length; - bucketStart = Arrays.copyOfRange(bucketStart, i, length); - if (activeTime != null) activeTime = Arrays.copyOfRange(activeTime, i, length); - if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length); - if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length); - if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length); - if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length); - if (operations != null) operations = Arrays.copyOfRange(operations, i, length); - bucketCount -= i; - - totalBytes = 0; - if (rxBytes != null) totalBytes += CollectionUtils.total(rxBytes); - if (txBytes != null) totalBytes += CollectionUtils.total(txBytes); - } - } - - /** - * Return interpolated data usage across the requested range. Interpolates - * across buckets, so values may be rounded slightly. - * - *

If the active bucket is not completed yet, it returns the proportional value of it - * based on its duration and the {@code end} param. - * - * @param start - start of the range, timestamp in milliseconds since the epoch. - * @param end - end of the range, timestamp in milliseconds since the epoch. - * @param recycle - entry instance for performance, could be null. - * @hide - */ - @UnsupportedAppUsage - public Entry getValues(long start, long end, Entry recycle) { - return getValues(start, end, Long.MAX_VALUE, recycle); - } - - /** - * Return interpolated data usage across the requested range. Interpolates - * across buckets, so values may be rounded slightly. - * - * @param start - start of the range, timestamp in milliseconds since the epoch. - * @param end - end of the range, timestamp in milliseconds since the epoch. - * @param now - current timestamp in milliseconds since the epoch (wall clock). - * @param recycle - entry instance for performance, could be null. - * @hide - */ - @UnsupportedAppUsage - public Entry getValues(long start, long end, long now, Entry recycle) { - final Entry entry = recycle != null ? recycle : new Entry(); - entry.bucketDuration = end - start; - entry.bucketStart = start; - entry.activeTime = activeTime != null ? 0 : UNKNOWN; - entry.rxBytes = rxBytes != null ? 0 : UNKNOWN; - entry.rxPackets = rxPackets != null ? 0 : UNKNOWN; - entry.txBytes = txBytes != null ? 0 : UNKNOWN; - entry.txPackets = txPackets != null ? 0 : UNKNOWN; - entry.operations = operations != null ? 0 : UNKNOWN; - - // Return fast if there is no entry. - if (bucketCount == 0) return entry; - - final int startIndex = getIndexAfter(end); - for (int i = startIndex; i >= 0; i--) { - final long curStart = bucketStart[i]; - long curEnd = curStart + bucketDuration; - - // bucket is older than request; we're finished - if (curEnd <= start) break; - // bucket is newer than request; keep looking - if (curStart >= end) continue; - - // the active bucket is shorter then a normal completed bucket - if (curEnd > now) curEnd = now; - // usually this is simply bucketDuration - final long bucketSpan = curEnd - curStart; - // prevent division by zero - if (bucketSpan <= 0) continue; - - final long overlapEnd = curEnd < end ? curEnd : end; - final long overlapStart = curStart > start ? curStart : start; - final long overlap = overlapEnd - overlapStart; - if (overlap <= 0) continue; - - // integer math each time is faster than floating point - if (activeTime != null) { - entry.activeTime += multiplySafeByRational(activeTime[i], overlap, bucketSpan); - } - if (rxBytes != null) { - entry.rxBytes += multiplySafeByRational(rxBytes[i], overlap, bucketSpan); - } - if (rxPackets != null) { - entry.rxPackets += multiplySafeByRational(rxPackets[i], overlap, bucketSpan); - } - if (txBytes != null) { - entry.txBytes += multiplySafeByRational(txBytes[i], overlap, bucketSpan); - } - if (txPackets != null) { - entry.txPackets += multiplySafeByRational(txPackets[i], overlap, bucketSpan); - } - if (operations != null) { - entry.operations += multiplySafeByRational(operations[i], overlap, bucketSpan); - } - } - return entry; - } - - /** - * @deprecated only for temporary testing - * @hide - */ - @Deprecated - public void generateRandom(long start, long end, long bytes) { - final Random r = new Random(); - - final float fractionRx = r.nextFloat(); - final long rxBytes = (long) (bytes * fractionRx); - final long txBytes = (long) (bytes * (1 - fractionRx)); - - final long rxPackets = rxBytes / 1024; - final long txPackets = txBytes / 1024; - final long operations = rxBytes / 2048; - - generateRandom(start, end, rxBytes, rxPackets, txBytes, txPackets, operations, r); - } - - /** - * @deprecated only for temporary testing - * @hide - */ - @Deprecated - public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes, - long txPackets, long operations, Random r) { - ensureBuckets(start, end); - - final NetworkStats.Entry entry = new NetworkStats.Entry( - IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); - while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128 - || operations > 32) { - final long curStart = randomLong(r, start, end); - final long curEnd = curStart + randomLong(r, 0, (end - curStart) / 2); - - entry.rxBytes = randomLong(r, 0, rxBytes); - entry.rxPackets = randomLong(r, 0, rxPackets); - entry.txBytes = randomLong(r, 0, txBytes); - entry.txPackets = randomLong(r, 0, txPackets); - entry.operations = randomLong(r, 0, operations); - - rxBytes -= entry.rxBytes; - rxPackets -= entry.rxPackets; - txBytes -= entry.txBytes; - txPackets -= entry.txPackets; - operations -= entry.operations; - - recordData(curStart, curEnd, entry); - } - } - - /** @hide */ - public static long randomLong(Random r, long start, long end) { - return (long) (start + (r.nextFloat() * (end - start))); - } - - /** - * Quickly determine if this history intersects with given window. - * @hide - */ - public boolean intersects(long start, long end) { - final long dataStart = getStart(); - final long dataEnd = getEnd(); - if (start >= dataStart && start <= dataEnd) return true; - if (end >= dataStart && end <= dataEnd) return true; - if (dataStart >= start && dataStart <= end) return true; - if (dataEnd >= start && dataEnd <= end) return true; - return false; - } - - /** @hide */ - public void dump(IndentingPrintWriter pw, boolean fullHistory) { - pw.print("NetworkStatsHistory: bucketDuration="); - pw.println(bucketDuration / SECOND_IN_MILLIS); - pw.increaseIndent(); - - final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32); - if (start > 0) { - pw.print("(omitting "); pw.print(start); pw.println(" buckets)"); - } - - for (int i = start; i < bucketCount; i++) { - pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS); - if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); } - if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); } - if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); } - if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); } - if (operations != null) { pw.print(" op="); pw.print(operations[i]); } - pw.println(); - } - - pw.decreaseIndent(); - } - - /** @hide */ - public void dumpCheckin(PrintWriter pw) { - pw.print("d,"); - pw.print(bucketDuration / SECOND_IN_MILLIS); - pw.println(); - - for (int i = 0; i < bucketCount; i++) { - pw.print("b,"); - pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(','); - if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(','); - if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(','); - if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(','); - if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(','); - if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); } - pw.println(); - } - } - - /** @hide */ - public void dumpDebug(ProtoOutputStream proto, long tag) { - final long start = proto.start(tag); - - proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); - - for (int i = 0; i < bucketCount; i++) { - final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); - - proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, - bucketStart[i]); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i); - - proto.end(startBucket); - } - - proto.end(start); - } - - private static void dumpDebug(ProtoOutputStream proto, long tag, long[] array, int index) { - if (array != null) { - proto.write(tag, array[index]); - } - } - - @Override - public String toString() { - final CharArrayWriter writer = new CharArrayWriter(); - dump(new IndentingPrintWriter(writer, " "), false); - return writer.toString(); - } - - @UnsupportedAppUsage - public static final @android.annotation.NonNull Creator CREATOR = new Creator() { - @Override - public NetworkStatsHistory createFromParcel(Parcel in) { - return new NetworkStatsHistory(in); - } - - @Override - public NetworkStatsHistory[] newArray(int size) { - return new NetworkStatsHistory[size]; - } - }; - - private static long getLong(long[] array, int i, long value) { - return array != null ? array[i] : value; - } - - private static void setLong(long[] array, int i, long value) { - if (array != null) array[i] = value; - } - - private static void addLong(long[] array, int i, long value) { - if (array != null) array[i] += value; - } - - /** @hide */ - public int estimateResizeBuckets(long newBucketDuration) { - return (int) (size() * getBucketDuration() / newBucketDuration); - } - - /** - * Utility methods for interacting with {@link DataInputStream} and - * {@link DataOutputStream}, mostly dealing with writing partial arrays. - * @hide - */ - public static class DataStreamUtils { - @Deprecated - public static long[] readFullLongArray(DataInput in) throws IOException { - final int size = in.readInt(); - if (size < 0) throw new ProtocolException("negative array size"); - final long[] values = new long[size]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readLong(); - } - return values; - } - - /** - * Read variable-length {@link Long} using protobuf-style approach. - */ - public static long readVarLong(DataInput in) throws IOException { - int shift = 0; - long result = 0; - while (shift < 64) { - byte b = in.readByte(); - result |= (long) (b & 0x7F) << shift; - if ((b & 0x80) == 0) - return result; - shift += 7; - } - throw new ProtocolException("malformed long"); - } - - /** - * Write variable-length {@link Long} using protobuf-style approach. - */ - public static void writeVarLong(DataOutput out, long value) throws IOException { - while (true) { - if ((value & ~0x7FL) == 0) { - out.writeByte((int) value); - return; - } else { - out.writeByte(((int) value & 0x7F) | 0x80); - value >>>= 7; - } - } - } - - public static long[] readVarLongArray(DataInput in) throws IOException { - final int size = in.readInt(); - if (size == -1) return null; - if (size < 0) throw new ProtocolException("negative array size"); - final long[] values = new long[size]; - for (int i = 0; i < values.length; i++) { - values[i] = readVarLong(in); - } - return values; - } - - public static void writeVarLongArray(DataOutput out, long[] values, int size) - throws IOException { - if (values == null) { - out.writeInt(-1); - return; - } - if (size > values.length) { - throw new IllegalArgumentException("size larger than length"); - } - out.writeInt(size); - for (int i = 0; i < size; i++) { - writeVarLong(out, values[i]); - } - } - } - - /** - * Utility methods for interacting with {@link Parcel} structures, mostly - * dealing with writing partial arrays. - * @hide - */ - public static class ParcelUtils { - public static long[] readLongArray(Parcel in) { - final int size = in.readInt(); - if (size == -1) return null; - final long[] values = new long[size]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readLong(); - } - return values; - } - - public static void writeLongArray(Parcel out, long[] values, int size) { - if (values == null) { - out.writeInt(-1); - return; - } - if (size > values.length) { - throw new IllegalArgumentException("size larger than length"); - } - out.writeInt(size); - for (int i = 0; i < size; i++) { - out.writeLong(values[i]); - } - } - } - - /** - * Builder class for {@link NetworkStatsHistory}. - */ - public static final class Builder { - private final long mBucketDuration; - private final List mBucketStart; - private final List mActiveTime; - private final List mRxBytes; - private final List mRxPackets; - private final List mTxBytes; - private final List mTxPackets; - private final List mOperations; - - /** - * Creates a new Builder with given bucket duration and initial capacity to construct - * {@link NetworkStatsHistory} objects. - * - * @param bucketDuration Duration of the buckets of the object, in milliseconds. - * @param initialCapacity Estimated number of records. - */ - public Builder(long bucketDuration, int initialCapacity) { - mBucketDuration = bucketDuration; - mBucketStart = new ArrayList<>(initialCapacity); - mActiveTime = new ArrayList<>(initialCapacity); - mRxBytes = new ArrayList<>(initialCapacity); - mRxPackets = new ArrayList<>(initialCapacity); - mTxBytes = new ArrayList<>(initialCapacity); - mTxPackets = new ArrayList<>(initialCapacity); - mOperations = new ArrayList<>(initialCapacity); - } - - /** - * Add an {@link Entry} into the {@link NetworkStatsHistory} instance. - * - * @param entry The target {@link Entry} object. - * @return The builder object. - */ - @NonNull - public Builder addEntry(@NonNull Entry entry) { - mBucketStart.add(entry.bucketStart); - mActiveTime.add(entry.activeTime); - mRxBytes.add(entry.rxBytes); - mRxPackets.add(entry.rxPackets); - mTxBytes.add(entry.txBytes); - mTxPackets.add(entry.txPackets); - mOperations.add(entry.operations); - return this; - } - - private static long sum(@NonNull List list) { - long sum = 0; - for (long entry : list) { - sum += entry; - } - return sum; - } - - /** - * Builds the instance of the {@link NetworkStatsHistory}. - * - * @return the built instance of {@link NetworkStatsHistory}. - */ - @NonNull - public NetworkStatsHistory build() { - return new NetworkStatsHistory(mBucketDuration, - CollectionUtils.toLongArray(mBucketStart), - CollectionUtils.toLongArray(mActiveTime), - CollectionUtils.toLongArray(mRxBytes), - CollectionUtils.toLongArray(mRxPackets), - CollectionUtils.toLongArray(mTxBytes), - CollectionUtils.toLongArray(mTxPackets), - CollectionUtils.toLongArray(mOperations), - mBucketStart.size(), - sum(mRxBytes) + sum(mTxBytes)); - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java deleted file mode 100644 index 7b5afd720016a..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java +++ /dev/null @@ -1,1119 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static android.net.ConnectivityManager.TYPE_BLUETOOTH; -import static android.net.ConnectivityManager.TYPE_ETHERNET; -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_PROXY; -import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.ConnectivityManager.TYPE_WIFI_P2P; -import static android.net.ConnectivityManager.TYPE_WIMAX; -import static android.net.NetworkIdentity.OEM_NONE; -import static android.net.NetworkIdentity.OEM_PAID; -import static android.net.NetworkIdentity.OEM_PRIVATE; -import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; -import static android.net.NetworkStats.DEFAULT_NETWORK_NO; -import static android.net.NetworkStats.DEFAULT_NETWORK_YES; -import static android.net.NetworkStats.METERED_ALL; -import static android.net.NetworkStats.METERED_NO; -import static android.net.NetworkStats.METERED_YES; -import static android.net.NetworkStats.ROAMING_ALL; -import static android.net.NetworkStats.ROAMING_NO; -import static android.net.NetworkStats.ROAMING_YES; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.app.usage.NetworkStatsManager; -import android.compat.annotation.UnsupportedAppUsage; -import android.net.wifi.WifiInfo; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.ArraySet; - -import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.NetworkIdentityUtils; -import com.android.net.module.util.NetworkStatsUtils; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -/** - * Predicate used to match {@link NetworkIdentity}, usually when collecting - * statistics. (It should probably have been named {@code NetworkPredicate}.) - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public final class NetworkTemplate implements Parcelable { - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "MATCH_" }, value = { - MATCH_MOBILE, - MATCH_WIFI, - MATCH_ETHERNET, - MATCH_BLUETOOTH, - MATCH_PROXY, - MATCH_CARRIER, - }) - public @interface TemplateMatchRule{} - - /** Match rule to match cellular networks with given Subscriber Ids. */ - public static final int MATCH_MOBILE = 1; - /** Match rule to match wifi networks. */ - public static final int MATCH_WIFI = 4; - /** Match rule to match ethernet networks. */ - public static final int MATCH_ETHERNET = 5; - /** - * Match rule to match all cellular networks. - * - * @hide - */ - public static final int MATCH_MOBILE_WILDCARD = 6; - /** - * Match rule to match all wifi networks. - * - * @hide - */ - public static final int MATCH_WIFI_WILDCARD = 7; - /** Match rule to match bluetooth networks. */ - public static final int MATCH_BLUETOOTH = 8; - /** - * Match rule to match networks with {@link ConnectivityManager#TYPE_PROXY} as the legacy - * network type. - */ - public static final int MATCH_PROXY = 9; - /** - * Match rule to match all networks with subscriberId inside the template. Some carriers - * may offer non-cellular networks like WiFi, which will be matched by this rule. - */ - public static final int MATCH_CARRIER = 10; - - // TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL. - /** @hide */ - public static final String WIFI_NETWORKID_ALL = null; - - /** - * Wi-Fi Network Key is never supposed to be null (if it is, it is a bug that - * should be fixed), so it's not possible to want to match null vs - * non-null. Therefore it's fine to use null as a sentinel for Wifi Network Key. - * - * @hide - */ - public static final String WIFI_NETWORK_KEY_ALL = WIFI_NETWORKID_ALL; - - /** - * Include all network types when filtering. This is meant to merge in with the - * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. - */ - public static final int NETWORK_TYPE_ALL = -1; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "OEM_MANAGED_" }, value = { - OEM_MANAGED_ALL, - OEM_MANAGED_NO, - OEM_MANAGED_YES, - OEM_MANAGED_PAID, - OEM_MANAGED_PRIVATE - }) - public @interface OemManaged{} - - /** - * Value to match both OEM managed and unmanaged networks (all networks). - */ - public static final int OEM_MANAGED_ALL = -1; - /** - * Value to match networks which are not OEM managed. - */ - public static final int OEM_MANAGED_NO = OEM_NONE; - /** - * Value to match any OEM managed network. - */ - public static final int OEM_MANAGED_YES = -2; - /** - * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}. - */ - public static final int OEM_MANAGED_PAID = OEM_PAID; - /** - * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}. - */ - public static final int OEM_MANAGED_PRIVATE = OEM_PRIVATE; - - private static boolean isKnownMatchRule(final int rule) { - switch (rule) { - case MATCH_MOBILE: - case MATCH_WIFI: - case MATCH_ETHERNET: - case MATCH_MOBILE_WILDCARD: - case MATCH_WIFI_WILDCARD: - case MATCH_BLUETOOTH: - case MATCH_PROXY: - case MATCH_CARRIER: - return true; - - default: - return false; - } - } - - /** - * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with - * the given IMSI. - * - * @hide - */ - @UnsupportedAppUsage - public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { - return new NetworkTemplate(MATCH_MOBILE, subscriberId, null); - } - - /** - * Template to match cellular networks with the given IMSI, {@code ratType} and - * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when - * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. - * - * @hide - */ - public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, - int ratType, int metered) { - if (TextUtils.isEmpty(subscriberId)) { - return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null /* subscriberId */, - null /* matchSubscriberIds */, - new String[0] /* matchWifiNetworkKeys */, metered, ROAMING_ALL, - DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[] { subscriberId }, - new String[0] /* matchWifiNetworkKeys */, - metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - - /** - * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, - * regardless of IMSI. - * - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static NetworkTemplate buildTemplateMobileWildcard() { - return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); - } - - /** - * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, - * regardless of key of the wifi network. - * - * @hide - */ - @UnsupportedAppUsage - public static NetworkTemplate buildTemplateWifiWildcard() { - // TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL - // and SUBSCRIBER_ID_MATCH_RULE_ALL. - return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); - } - - /** @hide */ - @Deprecated - @UnsupportedAppUsage - public static NetworkTemplate buildTemplateWifi() { - return buildTemplateWifiWildcard(); - } - - /** - * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the - * given key of the wifi network. - * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} - * to know details about the key. - * @hide - */ - public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) { - Objects.requireNonNull(wifiNetworkKey); - return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */, - new String[] { null } /* matchSubscriberIds */, - new String[] { wifiNetworkKey }, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL); - } - - /** - * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given - * key of the wifi network and IMSI. - * - * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless - * of key of the wifi network. - * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} - * to know details about the key. - * @param subscriberId the IMSI associated to this wifi network. - * - * @hide - */ - public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey, - @Nullable String subscriberId) { - return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId }, - wifiNetworkKey != null - ? new String[] { wifiNetworkKey } : new String[0], - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - - /** - * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style - * networks together. - * - * @hide - */ - @UnsupportedAppUsage - public static NetworkTemplate buildTemplateEthernet() { - return new NetworkTemplate(MATCH_ETHERNET, null, null); - } - - /** - * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style - * networks together. - * - * @hide - */ - public static NetworkTemplate buildTemplateBluetooth() { - return new NetworkTemplate(MATCH_BLUETOOTH, null, null); - } - - /** - * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style - * networks together. - * - * @hide - */ - public static NetworkTemplate buildTemplateProxy() { - return new NetworkTemplate(MATCH_PROXY, null, null); - } - - /** - * Template to match all metered carrier networks with the given IMSI. - * - * @hide - */ - public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) { - Objects.requireNonNull(subscriberId); - return new NetworkTemplate(MATCH_CARRIER, subscriberId, - new String[] { subscriberId }, - new String[0] /* matchWifiNetworkKeys */, - METERED_YES, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - - private final int mMatchRule; - private final String mSubscriberId; - - /** - * Ugh, templates are designed to target a single subscriber, but we might - * need to match several "merged" subscribers. These are the subscribers - * that should be considered to match this template. - *

- * Since the merge set is dynamic, it should not be persisted or - * used for determining equality. - */ - private final String[] mMatchSubscriberIds; - - @NonNull - private final String[] mMatchWifiNetworkKeys; - - // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. - private final int mMetered; - private final int mRoaming; - private final int mDefaultNetwork; - private final int mRatType; - /** - * The subscriber Id match rule defines how the template should match networks with - * specific subscriberId(s). See NetworkTemplate#SUBSCRIBER_ID_MATCH_RULE_* for more detail. - */ - private final int mSubscriberIdMatchRule; - - // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. - private final int mOemManaged; - - private static void checkValidSubscriberIdMatchRule(int matchRule, int subscriberIdMatchRule) { - switch (matchRule) { - case MATCH_MOBILE: - case MATCH_CARRIER: - // MOBILE and CARRIER templates must always specify a subscriber ID. - if (subscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL) { - throw new IllegalArgumentException("Invalid SubscriberIdMatchRule " - + "on match rule: " + getMatchRuleName(matchRule)); - } - return; - default: - return; - } - } - - /** @hide */ - // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) - @UnsupportedAppUsage - public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) { - this(matchRule, subscriberId, new String[] { subscriberId }, wifiNetworkKey); - } - - /** @hide */ - public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String wifiNetworkKey) { - // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates - // to metered networks. It is now possible to match mobile with any meteredness, but - // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this - //constructor passes METERED_YES for these types. - this(matchRule, subscriberId, matchSubscriberIds, - wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], - (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES - : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - - /** @hide */ - // TODO: Remove it after updating all of the caller. - public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int ratType, - int oemManaged) { - this(matchRule, subscriberId, matchSubscriberIds, - wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], - metered, roaming, defaultNetwork, ratType, oemManaged, - NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); - } - - /** @hide */ - public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String[] matchWifiNetworkKeys, int metered, int roaming, - int defaultNetwork, int ratType, int oemManaged, int subscriberIdMatchRule) { - Objects.requireNonNull(matchWifiNetworkKeys); - mMatchRule = matchRule; - mSubscriberId = subscriberId; - // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when - // mSubscriberId is null - mMatchSubscriberIds = matchSubscriberIds; - mMatchWifiNetworkKeys = matchWifiNetworkKeys; - mMetered = metered; - mRoaming = roaming; - mDefaultNetwork = defaultNetwork; - mRatType = ratType; - mOemManaged = oemManaged; - mSubscriberIdMatchRule = subscriberIdMatchRule; - checkValidSubscriberIdMatchRule(matchRule, subscriberIdMatchRule); - if (!isKnownMatchRule(matchRule)) { - throw new IllegalArgumentException("Unknown network template rule " + matchRule - + " will not match any identity."); - } - } - - private NetworkTemplate(Parcel in) { - mMatchRule = in.readInt(); - mSubscriberId = in.readString(); - mMatchSubscriberIds = in.createStringArray(); - mMatchWifiNetworkKeys = in.createStringArray(); - mMetered = in.readInt(); - mRoaming = in.readInt(); - mDefaultNetwork = in.readInt(); - mRatType = in.readInt(); - mOemManaged = in.readInt(); - mSubscriberIdMatchRule = in.readInt(); - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mMatchRule); - dest.writeString(mSubscriberId); - dest.writeStringArray(mMatchSubscriberIds); - dest.writeStringArray(mMatchWifiNetworkKeys); - dest.writeInt(mMetered); - dest.writeInt(mRoaming); - dest.writeInt(mDefaultNetwork); - dest.writeInt(mRatType); - dest.writeInt(mOemManaged); - dest.writeInt(mSubscriberIdMatchRule); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder("NetworkTemplate: "); - builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); - if (mSubscriberId != null) { - builder.append(", subscriberId=").append( - NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); - } - if (mMatchSubscriberIds != null) { - builder.append(", matchSubscriberIds=").append( - Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds))); - } - builder.append(", matchWifiNetworkKeys=").append(Arrays.toString(mMatchWifiNetworkKeys)); - if (mMetered != METERED_ALL) { - builder.append(", metered=").append(NetworkStats.meteredToString(mMetered)); - } - if (mRoaming != ROAMING_ALL) { - builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming)); - } - if (mDefaultNetwork != DEFAULT_NETWORK_ALL) { - builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( - mDefaultNetwork)); - } - if (mRatType != NETWORK_TYPE_ALL) { - builder.append(", ratType=").append(mRatType); - } - if (mOemManaged != OEM_MANAGED_ALL) { - builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); - } - builder.append(", subscriberIdMatchRule=") - .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule)); - return builder.toString(); - } - - @Override - public int hashCode() { - return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys), - mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged, mSubscriberIdMatchRule); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof NetworkTemplate) { - final NetworkTemplate other = (NetworkTemplate) obj; - return mMatchRule == other.mMatchRule - && Objects.equals(mSubscriberId, other.mSubscriberId) - && mMetered == other.mMetered - && mRoaming == other.mRoaming - && mDefaultNetwork == other.mDefaultNetwork - && mRatType == other.mRatType - && mOemManaged == other.mOemManaged - && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule - && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys); - } - return false; - } - - private static String subscriberIdMatchRuleToString(int rule) { - switch (rule) { - case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT: - return "EXACT_MATCH"; - case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL: - return "ALL"; - default: - return "Unknown rule " + rule; - } - } - - /** @hide */ - public boolean isMatchRuleMobile() { - switch (mMatchRule) { - case MATCH_MOBILE: - case MATCH_MOBILE_WILDCARD: - return true; - default: - return false; - } - } - - /** - * Get match rule of the template. See {@code MATCH_*}. - */ - @UnsupportedAppUsage - public int getMatchRule() { - // Wildcard rules are not exposed. For external callers, convert wildcard rules to - // exposed rules before returning. - switch (mMatchRule) { - case MATCH_MOBILE_WILDCARD: - return MATCH_MOBILE; - case MATCH_WIFI_WILDCARD: - return MATCH_WIFI; - default: - return mMatchRule; - } - } - - /** - * Get subscriber Id of the template. - * @hide - */ - @Nullable - @UnsupportedAppUsage - public String getSubscriberId() { - return mSubscriberId; - } - - /** - * Get set of subscriber Ids of the template. - */ - @NonNull - public Set getSubscriberIds() { - return new ArraySet<>(Arrays.asList(mMatchSubscriberIds)); - } - - /** - * Get the set of Wifi Network Keys of the template. - * See {@link WifiInfo#getNetworkKey()}. - */ - @NonNull - public Set getWifiNetworkKeys() { - return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys)); - } - - /** @hide */ - // TODO: Remove this and replace all callers with {@link #getWifiNetworkKeys()}. - @Nullable - public String getNetworkId() { - return getWifiNetworkKeys().isEmpty() ? null : getWifiNetworkKeys().iterator().next(); - } - - /** - * Get meteredness filter of the template. - */ - @NetworkStats.Meteredness - public int getMeteredness() { - return mMetered; - } - - /** - * Get roaming filter of the template. - */ - @NetworkStats.Roaming - public int getRoaming() { - return mRoaming; - } - - /** - * Get the default network status filter of the template. - */ - @NetworkStats.DefaultNetwork - public int getDefaultNetworkStatus() { - return mDefaultNetwork; - } - - /** - * Get the Radio Access Technology(RAT) type filter of the template. - */ - public int getRatType() { - return mRatType; - } - - /** - * Get the OEM managed filter of the template. See {@code OEM_MANAGED_*} or - * {@code android.net.NetworkIdentity#OEM_*}. - */ - @OemManaged - public int getOemManaged() { - return mOemManaged; - } - - /** - * Test if given {@link NetworkIdentity} matches this template. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public boolean matches(@NonNull NetworkIdentity ident) { - Objects.requireNonNull(ident); - if (!matchesMetered(ident)) return false; - if (!matchesRoaming(ident)) return false; - if (!matchesDefaultNetwork(ident)) return false; - if (!matchesOemNetwork(ident)) return false; - - switch (mMatchRule) { - case MATCH_MOBILE: - return matchesMobile(ident); - case MATCH_WIFI: - return matchesWifi(ident); - case MATCH_ETHERNET: - return matchesEthernet(ident); - case MATCH_MOBILE_WILDCARD: - return matchesMobileWildcard(ident); - case MATCH_WIFI_WILDCARD: - return matchesWifiWildcard(ident); - case MATCH_BLUETOOTH: - return matchesBluetooth(ident); - case MATCH_PROXY: - return matchesProxy(ident); - case MATCH_CARRIER: - return matchesCarrier(ident); - default: - // We have no idea what kind of network template we are, so we - // just claim not to match anything. - return false; - } - } - - private boolean matchesMetered(NetworkIdentity ident) { - return (mMetered == METERED_ALL) - || (mMetered == METERED_YES && ident.mMetered) - || (mMetered == METERED_NO && !ident.mMetered); - } - - private boolean matchesRoaming(NetworkIdentity ident) { - return (mRoaming == ROAMING_ALL) - || (mRoaming == ROAMING_YES && ident.mRoaming) - || (mRoaming == ROAMING_NO && !ident.mRoaming); - } - - private boolean matchesDefaultNetwork(NetworkIdentity ident) { - return (mDefaultNetwork == DEFAULT_NETWORK_ALL) - || (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork) - || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); - } - - private boolean matchesOemNetwork(NetworkIdentity ident) { - return (mOemManaged == OEM_MANAGED_ALL) - || (mOemManaged == OEM_MANAGED_YES - && ident.mOemManaged != OEM_NONE) - || (mOemManaged == ident.mOemManaged); - } - - private boolean matchesCollapsedRatType(NetworkIdentity ident) { - return mRatType == NETWORK_TYPE_ALL - || NetworkStatsManager.getCollapsedRatType(mRatType) - == NetworkStatsManager.getCollapsedRatType(ident.mRatType); - } - - /** - * Check if this template matches {@code subscriberId}. Returns true if this - * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a - * {@code mMatchSubscriberIds} array that contains {@code subscriberId}. - * - * @hide - */ - public boolean matchesSubscriberId(@Nullable String subscriberId) { - return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL - || CollectionUtils.contains(mMatchSubscriberIds, subscriberId); - } - - /** - * Check if network matches key of the wifi network. - * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is - * empty. - * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} - * to know details about the key. - */ - private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) { - Objects.requireNonNull(wifiNetworkKey); - return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) - || CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey); - } - - /** - * Check if mobile network matches IMSI. - */ - private boolean matchesMobile(NetworkIdentity ident) { - if (ident.mType == TYPE_WIMAX) { - // TODO: consider matching against WiMAX subscriber identity - return true; - } else { - return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds) - && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) - && matchesCollapsedRatType(ident); - } - } - - /** - * Check if matches Wi-Fi network template. - */ - private boolean matchesWifi(NetworkIdentity ident) { - switch (ident.mType) { - case TYPE_WIFI: - return matchesSubscriberId(ident.mSubscriberId) - && matchesWifiNetworkKey(ident.mWifiNetworkKey); - default: - return false; - } - } - - /** - * Check if matches Ethernet network template. - */ - private boolean matchesEthernet(NetworkIdentity ident) { - if (ident.mType == TYPE_ETHERNET) { - return true; - } - return false; - } - - /** - * Check if matches carrier network. The carrier networks means it includes the subscriberId. - */ - private boolean matchesCarrier(NetworkIdentity ident) { - return ident.mSubscriberId != null - && !CollectionUtils.isEmpty(mMatchSubscriberIds) - && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); - } - - private boolean matchesMobileWildcard(NetworkIdentity ident) { - if (ident.mType == TYPE_WIMAX) { - return true; - } else { - return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident); - } - } - - private boolean matchesWifiWildcard(NetworkIdentity ident) { - switch (ident.mType) { - case TYPE_WIFI: - case TYPE_WIFI_P2P: - return true; - default: - return false; - } - } - - /** - * Check if matches Bluetooth network template. - */ - private boolean matchesBluetooth(NetworkIdentity ident) { - if (ident.mType == TYPE_BLUETOOTH) { - return true; - } - return false; - } - - /** - * Check if matches Proxy network template. - */ - private boolean matchesProxy(NetworkIdentity ident) { - return ident.mType == TYPE_PROXY; - } - - private static String getMatchRuleName(int matchRule) { - switch (matchRule) { - case MATCH_MOBILE: - return "MOBILE"; - case MATCH_WIFI: - return "WIFI"; - case MATCH_ETHERNET: - return "ETHERNET"; - case MATCH_MOBILE_WILDCARD: - return "MOBILE_WILDCARD"; - case MATCH_WIFI_WILDCARD: - return "WIFI_WILDCARD"; - case MATCH_BLUETOOTH: - return "BLUETOOTH"; - case MATCH_PROXY: - return "PROXY"; - case MATCH_CARRIER: - return "CARRIER"; - default: - return "UNKNOWN(" + matchRule + ")"; - } - } - - private static String getOemManagedNames(int oemManaged) { - switch (oemManaged) { - case OEM_MANAGED_ALL: - return "OEM_MANAGED_ALL"; - case OEM_MANAGED_NO: - return "OEM_MANAGED_NO"; - case OEM_MANAGED_YES: - return "OEM_MANAGED_YES"; - default: - return NetworkIdentity.getOemManagedNames(oemManaged); - } - } - - /** - * Examine the given template and normalize it. - * We pick the "lowest" merged subscriber as the primary - * for key purposes, and expand the template to match all other merged - * subscribers. - *

- * For example, given an incoming template matching B, and the currently - * active merge set [A,B], we'd return a new template that primarily matches - * A, but also matches B. - * TODO: remove and use {@link #normalize(NetworkTemplate, List)}. - * - * @hide - */ - @UnsupportedAppUsage - public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { - return normalize(template, Arrays.asList(merged)); - } - - /** - * Examine the given template and normalize it. - * We pick the "lowest" merged subscriber as the primary - * for key purposes, and expand the template to match all other merged - * subscribers. - * - * There can be multiple merged subscriberIds for multi-SIM devices. - * - *

- * For example, given an incoming template matching B, and the currently - * active merge set [A,B], we'd return a new template that primarily matches - * A, but also matches B. - * - * @hide - */ - // TODO: @SystemApi when ready. - public static NetworkTemplate normalize(NetworkTemplate template, List mergedList) { - // Now there are several types of network which uses SubscriberId to store network - // information. For instances: - // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. - // The TYPE_CARRIER means that the network associate to specific carrier network. - - if (template.mSubscriberId == null) return template; - - for (String[] merged : mergedList) { - if (CollectionUtils.contains(merged, template.mSubscriberId)) { - // Requested template subscriber is part of the merge group; return - // a template that matches all merged subscribers. - final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys; - return new NetworkTemplate(template.mMatchRule, merged[0], merged, - CollectionUtils.isEmpty(matchWifiNetworkKeys) - ? null : matchWifiNetworkKeys[0]); - } - } - - return template; - } - - @UnsupportedAppUsage - public static final @android.annotation.NonNull Creator CREATOR = new Creator() { - @Override - public NetworkTemplate createFromParcel(Parcel in) { - return new NetworkTemplate(in); - } - - @Override - public NetworkTemplate[] newArray(int size) { - return new NetworkTemplate[size]; - } - }; - - /** - * Builder class for NetworkTemplate. - */ - public static final class Builder { - private final int mMatchRule; - // Use a SortedSet to provide a deterministic order when fetching the first one. - @NonNull - private final SortedSet mMatchSubscriberIds = - new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder())); - @NonNull - private final SortedSet mMatchWifiNetworkKeys = new TreeSet<>(); - - // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. - private int mMetered; - private int mRoaming; - private int mDefaultNetwork; - private int mRatType; - - // Bitfield containing OEM network properties {@code NetworkIdentity#OEM_*}. - private int mOemManaged; - - /** - * Creates a new Builder with given match rule to construct NetworkTemplate objects. - * - * @param matchRule the match rule of the template, see {@code MATCH_*}. - */ - public Builder(@TemplateMatchRule final int matchRule) { - assertRequestableMatchRule(matchRule); - // Initialize members with default values. - mMatchRule = matchRule; - mMetered = METERED_ALL; - mRoaming = ROAMING_ALL; - mDefaultNetwork = DEFAULT_NETWORK_ALL; - mRatType = NETWORK_TYPE_ALL; - mOemManaged = OEM_MANAGED_ALL; - } - - /** - * Set the Subscriber Ids. Calling this function with an empty set represents - * the intention of matching any Subscriber Ids. - * - * @param subscriberIds the list of Subscriber Ids. - * @return this builder. - */ - @NonNull - public Builder setSubscriberIds(@NonNull Set subscriberIds) { - Objects.requireNonNull(subscriberIds); - mMatchSubscriberIds.clear(); - mMatchSubscriberIds.addAll(subscriberIds); - return this; - } - - /** - * Set the Wifi Network Keys. Calling this function with an empty set represents - * the intention of matching any Wifi Network Key. - * - * @param wifiNetworkKeys the list of Wifi Network Key, - * see {@link WifiInfo#getNetworkKey()}. - * Or an empty list to match all networks. - * Note that {@code getNetworkKey()} might get null key - * when wifi disconnects. However, the caller should never invoke - * this function with a null Wifi Network Key since such statistics - * never exists. - * @return this builder. - */ - @NonNull - public Builder setWifiNetworkKeys(@NonNull Set wifiNetworkKeys) { - Objects.requireNonNull(wifiNetworkKeys); - for (String key : wifiNetworkKeys) { - if (key == null) { - throw new IllegalArgumentException("Null is not a valid key"); - } - } - mMatchWifiNetworkKeys.clear(); - mMatchWifiNetworkKeys.addAll(wifiNetworkKeys); - return this; - } - - /** - * Set the meteredness filter. - * - * @param metered the meteredness filter. - * @return this builder. - */ - @NonNull - public Builder setMeteredness(@NetworkStats.Meteredness int metered) { - mMetered = metered; - return this; - } - - /** - * Set the roaming filter. - * - * @param roaming the roaming filter. - * @return this builder. - */ - @NonNull - public Builder setRoaming(@NetworkStats.Roaming int roaming) { - mRoaming = roaming; - return this; - } - - /** - * Set the default network status filter. - * - * @param defaultNetwork the default network status filter. - * @return this builder. - */ - @NonNull - public Builder setDefaultNetworkStatus(@NetworkStats.DefaultNetwork int defaultNetwork) { - mDefaultNetwork = defaultNetwork; - return this; - } - - /** - * Set the Radio Access Technology(RAT) type filter. - * - * @param ratType the Radio Access Technology(RAT) type filter. Use - * {@link #NETWORK_TYPE_ALL} to include all network types when filtering. - * See {@code TelephonyManager.NETWORK_TYPE_*}. - * @return this builder. - */ - @NonNull - public Builder setRatType(int ratType) { - // Input will be validated with the match rule when building the template. - mRatType = ratType; - return this; - } - - /** - * Set the OEM managed filter. - * - * @param oemManaged the match rule to match different type of OEM managed network or - * unmanaged networks. See {@code OEM_MANAGED_*}. - * @return this builder. - */ - @NonNull - public Builder setOemManaged(@OemManaged int oemManaged) { - mOemManaged = oemManaged; - return this; - } - - /** - * Check whether the match rule is requestable. - * - * @param matchRule the target match rule to be checked. - */ - private static void assertRequestableMatchRule(final int matchRule) { - if (!isKnownMatchRule(matchRule) - || matchRule == MATCH_PROXY - || matchRule == MATCH_MOBILE_WILDCARD - || matchRule == MATCH_WIFI_WILDCARD) { - throw new IllegalArgumentException("Invalid match rule: " - + getMatchRuleName(matchRule)); - } - } - - private void assertRequestableParameters() { - validateWifiNetworkKeys(); - // TODO: Check all the input are legitimate. - } - - private void validateWifiNetworkKeys() { - if (mMatchRule != MATCH_WIFI && !mMatchWifiNetworkKeys.isEmpty()) { - throw new IllegalArgumentException("Trying to build non wifi match rule: " - + mMatchRule + " with wifi network keys"); - } - } - - /** - * For backward compatibility, deduce match rule to a wildcard match rule - * if the Subscriber Ids are empty. - */ - private int getWildcardDeducedMatchRule() { - if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) { - return MATCH_MOBILE_WILDCARD; - } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty() - && mMatchWifiNetworkKeys.isEmpty()) { - return MATCH_WIFI_WILDCARD; - } - return mMatchRule; - } - - /** - * Builds the instance of the NetworkTemplate. - * - * @return the built instance of NetworkTemplate. - */ - @NonNull - public NetworkTemplate build() { - assertRequestableParameters(); - final int subscriberIdMatchRule = mMatchSubscriberIds.isEmpty() - ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL - : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT; - return new NetworkTemplate(getWildcardDeducedMatchRule(), - mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(), - mMatchSubscriberIds.toArray(new String[0]), - mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming, - mDefaultNetwork, mRatType, mOemManaged, subscriberIdMatchRule); - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java deleted file mode 100644 index bc836d857e3ec..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java +++ /dev/null @@ -1,1148 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import android.annotation.NonNull; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.annotation.TestApi; -import android.app.DownloadManager; -import android.app.backup.BackupManager; -import android.app.usage.NetworkStatsManager; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.media.MediaPlayer; -import android.os.Binder; -import android.os.Build; -import android.os.RemoteException; -import android.os.StrictMode; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.DatagramSocket; -import java.net.Socket; -import java.net.SocketException; - -/** - * Class that provides network traffic statistics. These statistics include - * bytes transmitted and received and network packets transmitted and received, - * over all interfaces, over the mobile interface, and on a per-UID basis. - *

- * These statistics may not be available on all platforms. If the statistics are - * not supported by this device, {@link #UNSUPPORTED} will be returned. - *

- * Note that the statistics returned by this class reset and start from zero - * after every reboot. To access more robust historical network statistics data, - * use {@link NetworkStatsManager} instead. - */ -public class TrafficStats { - static { - System.loadLibrary("framework-connectivity-tiramisu-jni"); - } - - private static final String TAG = TrafficStats.class.getSimpleName(); - /** - * The return value to indicate that the device does not support the statistic. - */ - public final static int UNSUPPORTED = -1; - - /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ - @Deprecated - public static final long KB_IN_BYTES = 1024; - /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ - @Deprecated - public static final long MB_IN_BYTES = KB_IN_BYTES * 1024; - /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ - @Deprecated - public static final long GB_IN_BYTES = MB_IN_BYTES * 1024; - /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ - @Deprecated - public static final long TB_IN_BYTES = GB_IN_BYTES * 1024; - /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ - @Deprecated - public static final long PB_IN_BYTES = TB_IN_BYTES * 1024; - - /** - * Special UID value used when collecting {@link NetworkStatsHistory} for - * removed applications. - * - * @hide - */ - public static final int UID_REMOVED = -4; - - /** - * Special UID value used when collecting {@link NetworkStatsHistory} for - * tethering traffic. - * - * @hide - */ - public static final int UID_TETHERING = NetworkStats.UID_TETHERING; - - /** - * Tag values in this range are reserved for the network stack. The network stack is - * running as UID {@link android.os.Process.NETWORK_STACK_UID} when in the mainline - * module separate process, and as the system UID otherwise. - */ - /** @hide */ - @SystemApi - public static final int TAG_NETWORK_STACK_RANGE_START = 0xFFFFFD00; - /** @hide */ - @SystemApi - public static final int TAG_NETWORK_STACK_RANGE_END = 0xFFFFFEFF; - - /** - * Tags between 0xFFFFFF00 and 0xFFFFFFFF are reserved and used internally by system services - * like DownloadManager when performing traffic on behalf of an application. - */ - // Please note there is no enforcement of these constants, so do not rely on them to - // determine that the caller is a system caller. - /** @hide */ - @SystemApi - public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = 0xFFFFFF00; - /** @hide */ - @SystemApi - public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = 0xFFFFFF0F; - - /** - * Tag values between these ranges are reserved for the network stack to do traffic - * on behalf of applications. It is a subrange of the range above. - */ - /** @hide */ - @SystemApi - public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = 0xFFFFFF80; - /** @hide */ - @SystemApi - public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = 0xFFFFFF8F; - - /** - * Default tag value for {@link DownloadManager} traffic. - * - * @hide - */ - public static final int TAG_SYSTEM_DOWNLOAD = 0xFFFFFF01; - - /** - * Default tag value for {@link MediaPlayer} traffic. - * - * @hide - */ - public static final int TAG_SYSTEM_MEDIA = 0xFFFFFF02; - - /** - * Default tag value for {@link BackupManager} backup traffic; that is, - * traffic from the device to the storage backend. - * - * @hide - */ - public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03; - - /** - * Default tag value for {@link BackupManager} restore traffic; that is, - * app data retrieved from the storage backend at install time. - * - * @hide - */ - public static final int TAG_SYSTEM_RESTORE = 0xFFFFFF04; - - /** - * Default tag value for code (typically APKs) downloaded by an app store on - * behalf of the app, such as updates. - * - * @hide - */ - public static final int TAG_SYSTEM_APP = 0xFFFFFF05; - - // TODO : remove this constant when Wifi code is updated - /** @hide */ - public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42; - - private static INetworkStatsService sStatsService; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - private synchronized static INetworkStatsService getStatsService() { - if (sStatsService == null) { - throw new IllegalStateException("TrafficStats not initialized, uid=" - + Binder.getCallingUid()); - } - return sStatsService; - } - - /** - * Snapshot of {@link NetworkStats} when the currently active profiling - * session started, or {@code null} if no session active. - * - * @see #startDataProfiling(Context) - * @see #stopDataProfiling(Context) - */ - private static NetworkStats sActiveProfilingStart; - - private static Object sProfilingLock = new Object(); - - private static final String LOOPBACK_IFACE = "lo"; - - /** - * Initialization {@link TrafficStats} with the context, to - * allow {@link TrafficStats} to fetch the needed binder. - * - * @param context a long-lived context, such as the application context or system - * server context. - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - @SuppressLint("VisiblySynchronized") - public static synchronized void init(@NonNull final Context context) { - if (sStatsService != null) { - throw new IllegalStateException("TrafficStats is already initialized, uid=" - + Binder.getCallingUid()); - } - final NetworkStatsManager statsManager = - context.getSystemService(NetworkStatsManager.class); - if (statsManager == null) { - // TODO: Currently Process.isSupplemental is not working yet, because it depends on - // process to run in a certain UID range, which is not true for now. Change this - // to Log.wtf once Process.isSupplemental is ready. - Log.e(TAG, "TrafficStats not initialized, uid=" + Binder.getCallingUid()); - return; - } - sStatsService = statsManager.getBinder(); - } - - /** - * Attach the socket tagger implementation to the current process, to - * get notified when a socket's {@link FileDescriptor} is assigned to - * a thread. See {@link SocketTagger#set(SocketTagger)}. - * - * @hide - */ - @SystemApi(client = MODULE_LIBRARIES) - public static void attachSocketTagger() { - dalvik.system.SocketTagger.set(new SocketTagger()); - } - - private static class SocketTagger extends dalvik.system.SocketTagger { - - // TODO: set to false - private static final boolean LOGD = true; - - SocketTagger() { - } - - @Override - public void tag(FileDescriptor fd) throws SocketException { - final UidTag tagInfo = sThreadUidTag.get(); - if (LOGD) { - Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" - + Integer.toHexString(tagInfo.tag) + ", statsUid=" + tagInfo.uid); - } - if (tagInfo.tag == -1) { - StrictMode.noteUntaggedSocket(); - } - - if (tagInfo.tag == -1 && tagInfo.uid == -1) return; - final int errno = native_tagSocketFd(fd, tagInfo.tag, tagInfo.uid); - if (errno < 0) { - Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " - + tagInfo.tag + ", " - + tagInfo.uid + ") failed with errno" + errno); - } - } - - @Override - public void untag(FileDescriptor fd) throws SocketException { - if (LOGD) { - Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); - } - - final UidTag tagInfo = sThreadUidTag.get(); - if (tagInfo.tag == -1 && tagInfo.uid == -1) return; - - final int errno = native_untagSocketFd(fd); - if (errno < 0) { - Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); - } - } - } - - private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); - private static native int native_untagSocketFd(FileDescriptor fd); - - private static class UidTag { - public int tag = -1; - public int uid = -1; - } - - private static ThreadLocal sThreadUidTag = new ThreadLocal() { - @Override - protected UidTag initialValue() { - return new UidTag(); - } - }; - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. Only one active tag per thread is supported. - *

- * Changes only take effect during subsequent calls to - * {@link #tagSocket(Socket)}. - *

- * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and - * used internally by system services like {@link DownloadManager} when - * performing traffic on behalf of an application. - * - * @see #clearThreadStatsTag() - */ - public static void setThreadStatsTag(int tag) { - getAndSetThreadStatsTag(tag); - } - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. Only one active tag per thread is supported. - *

- * Changes only take effect during subsequent calls to - * {@link #tagSocket(Socket)}. - *

- * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and - * used internally by system services like {@link DownloadManager} when - * performing traffic on behalf of an application. - * - * @return the current tag for the calling thread, which can be used to - * restore any existing values after a nested operation is finished - */ - public static int getAndSetThreadStatsTag(int tag) { - final int old = sThreadUidTag.get().tag; - sThreadUidTag.get().tag = tag; - return old; - } - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. The tag used internally is well-defined to - * distinguish all backup-related traffic. - * - * @hide - */ - @SystemApi - public static void setThreadStatsTagBackup() { - setThreadStatsTag(TAG_SYSTEM_BACKUP); - } - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. The tag used internally is well-defined to - * distinguish all restore-related traffic. - * - * @hide - */ - @SystemApi - public static void setThreadStatsTagRestore() { - setThreadStatsTag(TAG_SYSTEM_RESTORE); - } - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. The tag used internally is well-defined to - * distinguish all code (typically APKs) downloaded by an app store on - * behalf of the app, such as updates. - * - * @hide - */ - @SystemApi - public static void setThreadStatsTagApp() { - setThreadStatsTag(TAG_SYSTEM_APP); - } - - /** - * Set active tag to use when accounting {@link Socket} traffic originating - * from the current thread. The tag used internally is well-defined to - * distinguish all download provider traffic. - * - * @hide - */ - @SystemApi - public static void setThreadStatsTagDownload() { - setThreadStatsTag(TAG_SYSTEM_DOWNLOAD); - } - - /** - * Get the active tag used when accounting {@link Socket} traffic originating - * from the current thread. Only one active tag per thread is supported. - * {@link #tagSocket(Socket)}. - * - * @see #setThreadStatsTag(int) - */ - public static int getThreadStatsTag() { - return sThreadUidTag.get().tag; - } - - /** - * Clear any active tag set to account {@link Socket} traffic originating - * from the current thread. - * - * @see #setThreadStatsTag(int) - */ - public static void clearThreadStatsTag() { - sThreadUidTag.get().tag = -1; - } - - /** - * Set specific UID to use when accounting {@link Socket} traffic - * originating from the current thread. Designed for use when performing an - * operation on behalf of another application, or when another application - * is performing operations on your behalf. - *

- * Any app can accept blame for traffic performed on a socket - * originally created by another app by calling this method with the - * {@link android.system.Os#getuid()} value. However, only apps holding the - * {@code android.Manifest.permission#UPDATE_DEVICE_STATS} permission may - * assign blame to another UIDs. - *

- * Changes only take effect during subsequent calls to - * {@link #tagSocket(Socket)}. - */ - @SuppressLint("RequiresPermission") - public static void setThreadStatsUid(int uid) { - sThreadUidTag.get().uid = uid; - } - - /** - * Get the active UID used when accounting {@link Socket} traffic originating - * from the current thread. Only one active tag per thread is supported. - * {@link #tagSocket(Socket)}. - * - * @see #setThreadStatsUid(int) - */ - public static int getThreadStatsUid() { - return sThreadUidTag.get().uid; - } - - /** - * Set specific UID to use when accounting {@link Socket} traffic - * originating from the current thread as the calling UID. Designed for use - * when another application is performing operations on your behalf. - *

- * Changes only take effect during subsequent calls to - * {@link #tagSocket(Socket)}. - * - * @removed - * @deprecated use {@link #setThreadStatsUid(int)} instead. - */ - @Deprecated - public static void setThreadStatsUidSelf() { - setThreadStatsUid(android.os.Process.myUid()); - } - - /** - * Clear any active UID set to account {@link Socket} traffic originating - * from the current thread. - * - * @see #setThreadStatsUid(int) - */ - @SuppressLint("RequiresPermission") - public static void clearThreadStatsUid() { - setThreadStatsUid(-1); - } - - /** - * Tag the given {@link Socket} with any statistics parameters active for - * the current thread. Subsequent calls always replace any existing - * parameters. When finished, call {@link #untagSocket(Socket)} to remove - * statistics parameters. - * - * @see #setThreadStatsTag(int) - */ - public static void tagSocket(Socket socket) throws SocketException { - SocketTagger.get().tag(socket); - } - - /** - * Remove any statistics parameters from the given {@link Socket}. - *

- * In Android 8.1 (API level 27) and lower, a socket is automatically - * untagged when it's sent to another process using binder IPC with a - * {@code ParcelFileDescriptor} container. In Android 9.0 (API level 28) - * and higher, the socket tag is kept when the socket is sent to another - * process using binder IPC. You can mimic the previous behavior by - * calling {@code untagSocket()} before sending the socket to another - * process. - */ - public static void untagSocket(Socket socket) throws SocketException { - SocketTagger.get().untag(socket); - } - - /** - * Tag the given {@link DatagramSocket} with any statistics parameters - * active for the current thread. Subsequent calls always replace any - * existing parameters. When finished, call - * {@link #untagDatagramSocket(DatagramSocket)} to remove statistics - * parameters. - * - * @see #setThreadStatsTag(int) - */ - public static void tagDatagramSocket(DatagramSocket socket) throws SocketException { - SocketTagger.get().tag(socket); - } - - /** - * Remove any statistics parameters from the given {@link DatagramSocket}. - */ - public static void untagDatagramSocket(DatagramSocket socket) throws SocketException { - SocketTagger.get().untag(socket); - } - - /** - * Tag the given {@link FileDescriptor} socket with any statistics - * parameters active for the current thread. Subsequent calls always replace - * any existing parameters. When finished, call - * {@link #untagFileDescriptor(FileDescriptor)} to remove statistics - * parameters. - * - * @see #setThreadStatsTag(int) - */ - public static void tagFileDescriptor(FileDescriptor fd) throws IOException { - SocketTagger.get().tag(fd); - } - - /** - * Remove any statistics parameters from the given {@link FileDescriptor} - * socket. - */ - public static void untagFileDescriptor(FileDescriptor fd) throws IOException { - SocketTagger.get().untag(fd); - } - - /** - * Start profiling data usage for current UID. Only one profiling session - * can be active at a time. - * - * @hide - */ - public static void startDataProfiling(Context context) { - synchronized (sProfilingLock) { - if (sActiveProfilingStart != null) { - throw new IllegalStateException("already profiling data"); - } - - // take snapshot in time; we calculate delta later - sActiveProfilingStart = getDataLayerSnapshotForUid(context); - } - } - - /** - * Stop profiling data usage for current UID. - * - * @return Detailed {@link NetworkStats} of data that occurred since last - * {@link #startDataProfiling(Context)} call. - * @hide - */ - public static NetworkStats stopDataProfiling(Context context) { - synchronized (sProfilingLock) { - if (sActiveProfilingStart == null) { - throw new IllegalStateException("not profiling data"); - } - - // subtract starting values and return delta - final NetworkStats profilingStop = getDataLayerSnapshotForUid(context); - final NetworkStats profilingDelta = NetworkStats.subtract( - profilingStop, sActiveProfilingStart, null, null); - sActiveProfilingStart = null; - return profilingDelta; - } - } - - /** - * Increment count of network operations performed under the accounting tag - * currently active on the calling thread. This can be used to derive - * bytes-per-operation. - * - * @param operationCount Number of operations to increment count by. - */ - public static void incrementOperationCount(int operationCount) { - final int tag = getThreadStatsTag(); - incrementOperationCount(tag, operationCount); - } - - /** - * Increment count of network operations performed under the given - * accounting tag. This can be used to derive bytes-per-operation. - * - * @param tag Accounting tag used in {@link #setThreadStatsTag(int)}. - * @param operationCount Number of operations to increment count by. - */ - public static void incrementOperationCount(int tag, int operationCount) { - final int uid = android.os.Process.myUid(); - try { - getStatsService().incrementOperationCount(uid, tag, operationCount); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - public static void closeQuietly(INetworkStatsSession session) { - // TODO: move to NetworkStatsService once it exists - if (session != null) { - try { - session.close(); - } catch (RuntimeException rethrown) { - throw rethrown; - } catch (Exception ignored) { - } - } - } - - private static long addIfSupported(long stat) { - return (stat == UNSUPPORTED) ? 0 : stat; - } - - /** - * Return number of packets transmitted across mobile networks since device - * boot. Counts packets across all mobile network interfaces, and always - * increases monotonically since device boot. Statistics are measured at the - * network layer, so they include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getMobileTxPackets() { - long total = 0; - for (String iface : getMobileIfaces()) { - total += addIfSupported(getTxPackets(iface)); - } - return total; - } - - /** - * Return number of packets received across mobile networks since device - * boot. Counts packets across all mobile network interfaces, and always - * increases monotonically since device boot. Statistics are measured at the - * network layer, so they include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getMobileRxPackets() { - long total = 0; - for (String iface : getMobileIfaces()) { - total += addIfSupported(getRxPackets(iface)); - } - return total; - } - - /** - * Return number of bytes transmitted across mobile networks since device - * boot. Counts packets across all mobile network interfaces, and always - * increases monotonically since device boot. Statistics are measured at the - * network layer, so they include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getMobileTxBytes() { - long total = 0; - for (String iface : getMobileIfaces()) { - total += addIfSupported(getTxBytes(iface)); - } - return total; - } - - /** - * Return number of bytes received across mobile networks since device boot. - * Counts packets across all mobile network interfaces, and always increases - * monotonically since device boot. Statistics are measured at the network - * layer, so they include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getMobileRxBytes() { - long total = 0; - for (String iface : getMobileIfaces()) { - total += addIfSupported(getRxBytes(iface)); - } - return total; - } - - /** {@hide} */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static long getMobileTcpRxPackets() { - long total = 0; - for (String iface : getMobileIfaces()) { - long stat = UNSUPPORTED; - try { - stat = getStatsService().getIfaceStats(iface, TYPE_TCP_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - total += addIfSupported(stat); - } - return total; - } - - /** {@hide} */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static long getMobileTcpTxPackets() { - long total = 0; - for (String iface : getMobileIfaces()) { - long stat = UNSUPPORTED; - try { - stat = getStatsService().getIfaceStats(iface, TYPE_TCP_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - total += addIfSupported(stat); - } - return total; - } - - /** - * Return the number of packets transmitted on the specified interface since the interface - * was created. Statistics are measured at the network layer, so both TCP and - * UDP usage are included. - * - * Note that the returned values are partial statistics that do not count data from several - * sources and do not apply several adjustments that are necessary for correctness, such - * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to - * determine whether traffic is being transferred on the specific interface but are not a - * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} - * APIs. - * - * @param iface The name of the interface. - * @return The number of transmitted packets. - */ - public static long getTxPackets(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the number of packets received on the specified interface since the interface was - * created. Statistics are measured at the network layer, so both TCP - * and UDP usage are included. - * - * Note that the returned values are partial statistics that do not count data from several - * sources and do not apply several adjustments that are necessary for correctness, such - * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to - * determine whether traffic is being transferred on the specific interface but are not a - * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} - * APIs. - * - * @param iface The name of the interface. - * @return The number of received packets. - */ - public static long getRxPackets(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the number of bytes transmitted on the specified interface since the interface - * was created. Statistics are measured at the network layer, so both TCP and - * UDP usage are included. - * - * Note that the returned values are partial statistics that do not count data from several - * sources and do not apply several adjustments that are necessary for correctness, such - * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to - * determine whether traffic is being transferred on the specific interface but are not a - * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} - * APIs. - * - * @param iface The name of the interface. - * @return The number of transmitted bytes. - */ - public static long getTxBytes(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the number of bytes received on the specified interface since the interface - * was created. Statistics are measured at the network layer, so both TCP - * and UDP usage are included. - * - * Note that the returned values are partial statistics that do not count data from several - * sources and do not apply several adjustments that are necessary for correctness, such - * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to - * determine whether traffic is being transferred on the specific interface but are not a - * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} - * APIs. - * - * @param iface The name of the interface. - * @return The number of received bytes. - */ - public static long getRxBytes(@NonNull String iface) { - try { - return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - @TestApi - public static long getLoopbackTxPackets() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - @TestApi - public static long getLoopbackRxPackets() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - @TestApi - public static long getLoopbackTxBytes() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - @TestApi - public static long getLoopbackRxBytes() { - try { - return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of packets transmitted since device boot. Counts packets - * across all network interfaces, and always increases monotonically since - * device boot. Statistics are measured at the network layer, so they - * include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getTotalTxPackets() { - try { - return getStatsService().getTotalStats(TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of packets received since device boot. Counts packets - * across all network interfaces, and always increases monotonically since - * device boot. Statistics are measured at the network layer, so they - * include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getTotalRxPackets() { - try { - return getStatsService().getTotalStats(TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of bytes transmitted since device boot. Counts packets - * across all network interfaces, and always increases monotonically since - * device boot. Statistics are measured at the network layer, so they - * include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getTotalTxBytes() { - try { - return getStatsService().getTotalStats(TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of bytes received since device boot. Counts packets across - * all network interfaces, and always increases monotonically since device - * boot. Statistics are measured at the network layer, so they include both - * TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - */ - public static long getTotalRxBytes() { - try { - return getStatsService().getTotalStats(TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of bytes transmitted by the given UID since device boot. - * Counts packets across all network interfaces, and always increases - * monotonically since device boot. Statistics are measured at the network - * layer, so they include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may - * return {@link #UNSUPPORTED} on devices where statistics aren't available. - *

- * Starting in {@link android.os.Build.VERSION_CODES#N} this will only - * report traffic statistics for the calling UID. It will return - * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access - * historical network statistics belonging to other UIDs, use - * {@link NetworkStatsManager}. - * - * @see android.os.Process#myUid() - * @see android.content.pm.ApplicationInfo#uid - */ - public static long getUidTxBytes(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of bytes received by the given UID since device boot. - * Counts packets across all network interfaces, and always increases - * monotonically since device boot. Statistics are measured at the network - * layer, so they include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return - * {@link #UNSUPPORTED} on devices where statistics aren't available. - *

- * Starting in {@link android.os.Build.VERSION_CODES#N} this will only - * report traffic statistics for the calling UID. It will return - * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access - * historical network statistics belonging to other UIDs, use - * {@link NetworkStatsManager}. - * - * @see android.os.Process#myUid() - * @see android.content.pm.ApplicationInfo#uid - */ - public static long getUidRxBytes(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of packets transmitted by the given UID since device boot. - * Counts packets across all network interfaces, and always increases - * monotonically since device boot. Statistics are measured at the network - * layer, so they include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return - * {@link #UNSUPPORTED} on devices where statistics aren't available. - *

- * Starting in {@link android.os.Build.VERSION_CODES#N} this will only - * report traffic statistics for the calling UID. It will return - * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access - * historical network statistics belonging to other UIDs, use - * {@link NetworkStatsManager}. - * - * @see android.os.Process#myUid() - * @see android.content.pm.ApplicationInfo#uid - */ - public static long getUidTxPackets(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return number of packets received by the given UID since device boot. - * Counts packets across all network interfaces, and always increases - * monotonically since device boot. Statistics are measured at the network - * layer, so they include both TCP and UDP usage. - *

- * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return - * {@link #UNSUPPORTED} on devices where statistics aren't available. - *

- * Starting in {@link android.os.Build.VERSION_CODES#N} this will only - * report traffic statistics for the calling UID. It will return - * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access - * historical network statistics belonging to other UIDs, use - * {@link NetworkStatsManager}. - * - * @see android.os.Process#myUid() - * @see android.content.pm.ApplicationInfo#uid - */ - public static long getUidRxPackets(int uid) { - try { - return getStatsService().getUidStats(uid, TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidTxBytes(int) - */ - @Deprecated - public static long getUidTcpTxBytes(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidRxBytes(int) - */ - @Deprecated - public static long getUidTcpRxBytes(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidTxBytes(int) - */ - @Deprecated - public static long getUidUdpTxBytes(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidRxBytes(int) - */ - @Deprecated - public static long getUidUdpRxBytes(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidTxPackets(int) - */ - @Deprecated - public static long getUidTcpTxSegments(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidRxPackets(int) - */ - @Deprecated - public static long getUidTcpRxSegments(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidTxPackets(int) - */ - @Deprecated - public static long getUidUdpTxPackets(int uid) { - return UNSUPPORTED; - } - - /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, - * transport layer statistics are no longer available, and will - * always return {@link #UNSUPPORTED}. - * @see #getUidRxPackets(int) - */ - @Deprecated - public static long getUidUdpRxPackets(int uid) { - return UNSUPPORTED; - } - - /** - * Return detailed {@link NetworkStats} for the current UID. Requires no - * special permission. - */ - private static NetworkStats getDataLayerSnapshotForUid(Context context) { - // TODO: take snapshot locally, since proc file is now visible - final int uid = android.os.Process.myUid(); - try { - return getStatsService().getDataLayerSnapshotForUid(uid); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return set of any ifaces associated with mobile networks since boot. - * Interfaces are never removed from this list, so counters should always be - * monotonic. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) - private static String[] getMobileIfaces() { - try { - return getStatsService().getMobileIfaces(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - // NOTE: keep these in sync with {@code com_android_server_net_NetworkStatsService.cpp}. - /** {@hide} */ - public static final int TYPE_RX_BYTES = 0; - /** {@hide} */ - public static final int TYPE_RX_PACKETS = 1; - /** {@hide} */ - public static final int TYPE_TX_BYTES = 2; - /** {@hide} */ - public static final int TYPE_TX_PACKETS = 3; - /** {@hide} */ - public static final int TYPE_TCP_RX_PACKETS = 4; - /** {@hide} */ - public static final int TYPE_TCP_TX_PACKETS = 5; -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl b/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl deleted file mode 100644 index a56f2f40583b6..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (C) 2015 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; - -parcelable UnderlyingNetworkInfo; diff --git a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java b/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java deleted file mode 100644 index 33f9375c03bfb..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/UnderlyingNetworkInfo.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2015 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; - -import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.os.Parcel; -import android.os.Parcelable; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -/** - * A lightweight container used to carry information on the networks that underly a given - * virtual network. - * - * @hide - */ -@SystemApi(client = MODULE_LIBRARIES) -public final class UnderlyingNetworkInfo implements Parcelable { - /** The owner of this network. */ - private final int mOwnerUid; - - /** The interface name of this network. */ - @NonNull - private final String mIface; - - /** The names of the interfaces underlying this network. */ - @NonNull - private final List mUnderlyingIfaces; - - public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface, - @NonNull List underlyingIfaces) { - Objects.requireNonNull(iface); - Objects.requireNonNull(underlyingIfaces); - mOwnerUid = ownerUid; - mIface = iface; - mUnderlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces)); - } - - private UnderlyingNetworkInfo(@NonNull Parcel in) { - mOwnerUid = in.readInt(); - mIface = in.readString(); - List underlyingIfaces = new ArrayList<>(); - in.readList(underlyingIfaces, null /*classLoader*/); - mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces); - } - - /** Get the owner of this network. */ - public int getOwnerUid() { - return mOwnerUid; - } - - /** Get the interface name of this network. */ - @NonNull - public String getInterface() { - return mIface; - } - - /** Get the names of the interfaces underlying this network. */ - @NonNull - public List getUnderlyingInterfaces() { - return mUnderlyingIfaces; - } - - @Override - public String toString() { - return "UnderlyingNetworkInfo{" - + "ownerUid=" + mOwnerUid - + ", iface='" + mIface + '\'' - + ", underlyingIfaces='" + mUnderlyingIfaces.toString() + '\'' - + '}'; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mOwnerUid); - dest.writeString(mIface); - dest.writeList(mUnderlyingIfaces); - } - - @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @NonNull - @Override - public UnderlyingNetworkInfo createFromParcel(@NonNull Parcel in) { - return new UnderlyingNetworkInfo(in); - } - - @NonNull - @Override - public UnderlyingNetworkInfo[] newArray(int size) { - return new UnderlyingNetworkInfo[size]; - } - }; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof UnderlyingNetworkInfo)) return false; - final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o; - return mOwnerUid == that.getOwnerUid() - && Objects.equals(mIface, that.getInterface()) - && Objects.equals(mUnderlyingIfaces, that.getUnderlyingInterfaces()); - } - - @Override - public int hashCode() { - return Objects.hash(mOwnerUid, mIface, mUnderlyingIfaces); - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/IUsageCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/IUsageCallback.aidl deleted file mode 100644 index 4e8a5b23093a1..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/netstats/IUsageCallback.aidl +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2022 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.netstats; - -import android.net.DataUsageRequest; - -/** - * Interface for NetworkStatsService to notify events to the callers of registerUsageCallback. - * - * @hide - */ -oneway interface IUsageCallback { - void onThresholdReached(in DataUsageRequest request); - void onCallbackReleased(in DataUsageRequest request); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl deleted file mode 100644 index 74c3ba44b69e8..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 android.net.netstats.provider; - -/** - * Interface for NetworkStatsService to query network statistics and set data limits. - * - * @hide - */ -oneway interface INetworkStatsProvider { - void onRequestStatsUpdate(int token); - void onSetAlert(long quotaBytes); - void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl deleted file mode 100644 index 01ff02dfc5b3c..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 android.net.netstats.provider; - -import android.net.NetworkStats; - -/** - * Interface for implementor of {@link INetworkStatsProviderCallback} to push events - * such as network statistics update or notify limit reached. - * @hide - */ -oneway interface INetworkStatsProviderCallback { - void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); - void notifyAlertReached(); - void notifyWarningReached(); - void notifyLimitReached(); - void unregister(); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java deleted file mode 100644 index d37a53dbf1e9d..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * 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 android.net.netstats.provider; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.SystemApi; -import android.net.NetworkStats; -import android.os.RemoteException; - -/** - * A base class that allows external modules to implement a custom network statistics provider. - * @hide - */ -@SystemApi -public abstract class NetworkStatsProvider { - /** - * A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit} - * indicates there is no limit. - */ - public static final int QUOTA_UNLIMITED = -1; - - @NonNull private final INetworkStatsProvider mProviderBinder = - new INetworkStatsProvider.Stub() { - - @Override - public void onRequestStatsUpdate(int token) { - NetworkStatsProvider.this.onRequestStatsUpdate(token); - } - - @Override - public void onSetAlert(long quotaBytes) { - NetworkStatsProvider.this.onSetAlert(quotaBytes); - } - - @Override - public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) { - NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes); - } - }; - - // The binder given by the service when successfully registering. Only null before registering, - // never null once non-null. - @Nullable - private INetworkStatsProviderCallback mProviderCbBinder; - - /** - * Return the binder invoked by the service and redirect function calls to the overridden - * methods. - * @hide - */ - @NonNull - public INetworkStatsProvider getProviderBinder() { - return mProviderBinder; - } - - /** - * Store the binder that was returned by the service when successfully registering. Note that - * the provider cannot be re-registered. Hence this method can only be called once per provider. - * - * @hide - */ - public void setProviderCallbackBinder(@NonNull INetworkStatsProviderCallback binder) { - if (mProviderCbBinder != null) { - throw new IllegalArgumentException("provider is already registered"); - } - mProviderCbBinder = binder; - } - - /** - * Get the binder that was returned by the service when successfully registering. Or null if the - * provider was never registered. - * - * @hide - */ - @Nullable - public INetworkStatsProviderCallback getProviderCallbackBinder() { - return mProviderCbBinder; - } - - /** - * Get the binder that was returned by the service when successfully registering. Throw an - * {@link IllegalStateException} if the provider is not registered. - * - * @hide - */ - @NonNull - public INetworkStatsProviderCallback getProviderCallbackBinderOrThrow() { - if (mProviderCbBinder == null) { - throw new IllegalStateException("the provider is not registered"); - } - return mProviderCbBinder; - } - - /** - * Notify the system of new network statistics. - * - * Send the network statistics recorded since the last call to {@link #notifyStatsUpdated}. Must - * be called as soon as possible after {@link NetworkStatsProvider#onRequestStatsUpdate(int)} - * being called. Responding later increases the probability stats will be dropped. The - * provider can also call this whenever it wants to reports new stats for any reason. - * Note that the system will not necessarily immediately propagate the statistics to - * reflect the update. - * - * @param token the token under which these stats were gathered. Providers can call this method - * with the current token as often as they want, until the token changes. - * {@see NetworkStatsProvider#onRequestStatsUpdate()} - * @param ifaceStats the {@link NetworkStats} per interface to be reported. - * The provider should not include any traffic that is already counted by - * kernel interface counters. - * @param uidStats the same stats as above, but counts {@link NetworkStats} - * per uid. - */ - public void notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats, - @NonNull NetworkStats uidStats) { - try { - getProviderCallbackBinderOrThrow().notifyStatsUpdated(token, ifaceStats, uidStats); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Notify system that the quota set by {@code onSetAlert} has been reached. - */ - public void notifyAlertReached() { - try { - getProviderCallbackBinderOrThrow().notifyAlertReached(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached. - */ - public void notifyWarningReached() { - try { - // Reuse the code path to notify warning reached with limit reached - // since framework handles them in the same way. - getProviderCallbackBinderOrThrow().notifyWarningReached(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Notify system that the limit set by {@link #onSetLimit} or limit set by - * {@link #onSetWarningAndLimit} has been reached. - */ - public void notifyLimitReached() { - try { - getProviderCallbackBinderOrThrow().notifyLimitReached(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Called by {@code NetworkStatsService} when it requires to know updated stats. - * The provider MUST respond by calling {@link #notifyStatsUpdated} as soon as possible. - * Responding later increases the probability stats will be dropped. Memory allowing, the - * system will try to take stats into account up to one minute after calling - * {@link #onRequestStatsUpdate}. - * - * @param token a positive number identifying the new state of the system under which - * {@link NetworkStats} have to be gathered from now on. When this is called, - * custom implementations of providers MUST tally and report the latest stats with - * the previous token, under which stats were being gathered so far. - */ - public abstract void onRequestStatsUpdate(int token); - - /** - * Called by {@code NetworkStatsService} when setting the interface quota for the specified - * upstream interface. When this is called, the custom implementation should block all egress - * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have - * been reached, and MUST respond to it by calling - * {@link NetworkStatsProvider#notifyLimitReached()}. - * - * @param iface the interface requiring the operation. - * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting - * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. - */ - public abstract void onSetLimit(@NonNull String iface, long quotaBytes); - - /** - * Called by {@code NetworkStatsService} when setting the interface quotas for the specified - * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system - * will not call {@link #onSetLimit}. When this method is called, the implementation - * should behave as follows: - * 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on - * {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}. - * 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on - * {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}. - * - * @param iface the interface requiring the operation. - * @param warningBytes the warning defined as the number of bytes, starting from zero and - * counting from now. A value of {@link #QUOTA_UNLIMITED} indicates - * there is no warning. - * @param limitBytes the limit defined as the number of bytes, starting from zero and counting - * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. - */ - public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) { - // Backward compatibility for those who didn't override this function. - onSetLimit(iface, limitBytes); - } - - /** - * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations - * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes - * have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should - * not block all egress packets. - * - * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting - * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert. - */ - public abstract void onSetAlert(long quotaBytes); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManager.aidl b/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManager.aidl deleted file mode 100644 index 89e9cdbd4445e..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManager.aidl +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2021, 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.nsd; - -import android.net.nsd.INsdManagerCallback; -import android.net.nsd.INsdServiceConnector; -import android.os.Messenger; - -/** - * Interface that NsdService implements to connect NsdManager clients. - * - * {@hide} - */ -interface INsdManager { - INsdServiceConnector connect(INsdManagerCallback cb); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManagerCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManagerCallback.aidl deleted file mode 100644 index 1a262ec0e9dd2..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdManagerCallback.aidl +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2021, 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.nsd; - -import android.os.Messenger; -import android.net.nsd.NsdServiceInfo; - -/** - * Callbacks from NsdService to NsdManager - * @hide - */ -oneway interface INsdManagerCallback { - void onDiscoverServicesStarted(int listenerKey, in NsdServiceInfo info); - void onDiscoverServicesFailed(int listenerKey, int error); - void onServiceFound(int listenerKey, in NsdServiceInfo info); - void onServiceLost(int listenerKey, in NsdServiceInfo info); - void onStopDiscoveryFailed(int listenerKey, int error); - void onStopDiscoverySucceeded(int listenerKey); - void onRegisterServiceFailed(int listenerKey, int error); - void onRegisterServiceSucceeded(int listenerKey, in NsdServiceInfo info); - void onUnregisterServiceFailed(int listenerKey, int error); - void onUnregisterServiceSucceeded(int listenerKey); - void onResolveServiceFailed(int listenerKey, int error); - void onResolveServiceSucceeded(int listenerKey, in NsdServiceInfo info); -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdServiceConnector.aidl b/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdServiceConnector.aidl deleted file mode 100644 index b06ae55b150e2..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/INsdServiceConnector.aidl +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2021, 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.nsd; - -import android.net.nsd.INsdManagerCallback; -import android.net.nsd.NsdServiceInfo; -import android.os.Messenger; - -/** - * Interface that NsdService implements for each NsdManager client. - * - * {@hide} - */ -interface INsdServiceConnector { - void registerService(int listenerKey, in NsdServiceInfo serviceInfo); - void unregisterService(int listenerKey); - void discoverServices(int listenerKey, in NsdServiceInfo serviceInfo); - void stopDiscovery(int listenerKey); - void resolveService(int listenerKey, in NsdServiceInfo serviceInfo); - void startDaemon(); -} \ No newline at end of file diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java deleted file mode 100644 index 209f372fd3772..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java +++ /dev/null @@ -1,1083 +0,0 @@ -/* - * Copyright (C) 2021 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.nsd; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.SystemService; -import android.app.compat.CompatChanges; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.net.NetworkRequest; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.os.RemoteException; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Log; -import android.util.SparseArray; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.Objects; -import java.util.concurrent.Executor; - -/** - * The Network Service Discovery Manager class provides the API to discover services - * on a network. As an example, if device A and device B are connected over a Wi-Fi - * network, a game registered on device A can be discovered by a game on device - * B. Another example use case is an application discovering printers on the network. - * - *

The API currently supports DNS based service discovery and discovery is currently - * limited to a local network over Multicast DNS. DNS service discovery is described at - * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt - * - *

The API is asynchronous, and responses to requests from an application are on listener - * callbacks on a separate internal thread. - * - *

There are three main operations the API supports - registration, discovery and resolution. - *

- *                          Application start
- *                                 |
- *                                 |
- *                                 |                  onServiceRegistered()
- *                     Register any local services  /
- *                      to be advertised with       \
- *                       registerService()            onRegistrationFailed()
- *                                 |
- *                                 |
- *                          discoverServices()
- *                                 |
- *                      Maintain a list to track
- *                        discovered services
- *                                 |
- *                                 |--------->
- *                                 |          |
- *                                 |      onServiceFound()
- *                                 |          |
- *                                 |     add service to list
- *                                 |          |
- *                                 |<----------
- *                                 |
- *                                 |--------->
- *                                 |          |
- *                                 |      onServiceLost()
- *                                 |          |
- *                                 |   remove service from list
- *                                 |          |
- *                                 |<----------
- *                                 |
- *                                 |
- *                                 | Connect to a service
- *                                 | from list ?
- *                                 |
- *                          resolveService()
- *                                 |
- *                         onServiceResolved()
- *                                 |
- *                     Establish connection to service
- *                     with the host and port information
- *
- * 
- * An application that needs to advertise itself over a network for other applications to - * discover it can do so with a call to {@link #registerService}. If Example is a http based - * application that can provide HTML data to peer services, it can register a name "Example" - * with service type "_http._tcp". A successful registration is notified with a callback to - * {@link RegistrationListener#onServiceRegistered} and a failure to register is notified - * over {@link RegistrationListener#onRegistrationFailed} - * - *

A peer application looking for http services can initiate a discovery for "_http._tcp" - * with a call to {@link #discoverServices}. A service found is notified with a callback - * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on - * {@link DiscoveryListener#onServiceLost}. - * - *

Once the peer application discovers the "Example" http service, and either needs to read the - * attributes of the service or wants to receive data from the "Example" application, it can - * initiate a resolve with {@link #resolveService} to resolve the attributes, host, and port - * details. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a - * failure is notified on {@link ResolveListener#onResolveFailed}. - * - * Applications can reserve for a service type at - * http://www.iana.org/form/ports-service. Existing services can be found at - * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml - * - * {@see NsdServiceInfo} - */ -@SystemService(Context.NSD_SERVICE) -public final class NsdManager { - private static final String TAG = NsdManager.class.getSimpleName(); - private static final boolean DBG = false; - - /** - * When enabled, apps targeting < Android 12 are considered legacy for - * the NSD native daemon. - * The platform will only keep the daemon running as long as there are - * any legacy apps connected. - * - * After Android 12, directly communicate with native daemon might not - * work since the native damon won't always stay alive. - * Use the NSD APIs from NsdManager as the replacement is recommended. - * An another alternative could be bundling your own mdns solutions instead of - * depending on the system mdns native daemon. - * - * @hide - */ - @ChangeId - @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S) - public static final long RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS = 191844585L; - - /** - * Broadcast intent action to indicate whether network service discovery is - * enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state - * information as int. - * - * @see #EXTRA_NSD_STATE - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED"; - - /** - * The lookup key for an int that indicates whether network service discovery is enabled - * or disabled. Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}. - * - * @see #NSD_STATE_DISABLED - * @see #NSD_STATE_ENABLED - */ - public static final String EXTRA_NSD_STATE = "nsd_state"; - - /** - * Network service discovery is disabled - * - * @see #ACTION_NSD_STATE_CHANGED - */ - public static final int NSD_STATE_DISABLED = 1; - - /** - * Network service discovery is enabled - * - * @see #ACTION_NSD_STATE_CHANGED - */ - public static final int NSD_STATE_ENABLED = 2; - - /** @hide */ - public static final int DISCOVER_SERVICES = 1; - /** @hide */ - public static final int DISCOVER_SERVICES_STARTED = 2; - /** @hide */ - public static final int DISCOVER_SERVICES_FAILED = 3; - /** @hide */ - public static final int SERVICE_FOUND = 4; - /** @hide */ - public static final int SERVICE_LOST = 5; - - /** @hide */ - public static final int STOP_DISCOVERY = 6; - /** @hide */ - public static final int STOP_DISCOVERY_FAILED = 7; - /** @hide */ - public static final int STOP_DISCOVERY_SUCCEEDED = 8; - - /** @hide */ - public static final int REGISTER_SERVICE = 9; - /** @hide */ - public static final int REGISTER_SERVICE_FAILED = 10; - /** @hide */ - public static final int REGISTER_SERVICE_SUCCEEDED = 11; - - /** @hide */ - public static final int UNREGISTER_SERVICE = 12; - /** @hide */ - public static final int UNREGISTER_SERVICE_FAILED = 13; - /** @hide */ - public static final int UNREGISTER_SERVICE_SUCCEEDED = 14; - - /** @hide */ - public static final int RESOLVE_SERVICE = 15; - /** @hide */ - public static final int RESOLVE_SERVICE_FAILED = 16; - /** @hide */ - public static final int RESOLVE_SERVICE_SUCCEEDED = 17; - - /** @hide */ - public static final int DAEMON_CLEANUP = 18; - - /** @hide */ - public static final int DAEMON_STARTUP = 19; - - /** @hide */ - public static final int ENABLE = 20; - /** @hide */ - public static final int DISABLE = 21; - - /** @hide */ - public static final int NATIVE_DAEMON_EVENT = 22; - - /** @hide */ - public static final int REGISTER_CLIENT = 23; - /** @hide */ - public static final int UNREGISTER_CLIENT = 24; - - /** Dns based service discovery protocol */ - public static final int PROTOCOL_DNS_SD = 0x0001; - - private static final SparseArray EVENT_NAMES = new SparseArray<>(); - static { - EVENT_NAMES.put(DISCOVER_SERVICES, "DISCOVER_SERVICES"); - EVENT_NAMES.put(DISCOVER_SERVICES_STARTED, "DISCOVER_SERVICES_STARTED"); - EVENT_NAMES.put(DISCOVER_SERVICES_FAILED, "DISCOVER_SERVICES_FAILED"); - EVENT_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND"); - EVENT_NAMES.put(SERVICE_LOST, "SERVICE_LOST"); - EVENT_NAMES.put(STOP_DISCOVERY, "STOP_DISCOVERY"); - EVENT_NAMES.put(STOP_DISCOVERY_FAILED, "STOP_DISCOVERY_FAILED"); - EVENT_NAMES.put(STOP_DISCOVERY_SUCCEEDED, "STOP_DISCOVERY_SUCCEEDED"); - EVENT_NAMES.put(REGISTER_SERVICE, "REGISTER_SERVICE"); - EVENT_NAMES.put(REGISTER_SERVICE_FAILED, "REGISTER_SERVICE_FAILED"); - EVENT_NAMES.put(REGISTER_SERVICE_SUCCEEDED, "REGISTER_SERVICE_SUCCEEDED"); - EVENT_NAMES.put(UNREGISTER_SERVICE, "UNREGISTER_SERVICE"); - EVENT_NAMES.put(UNREGISTER_SERVICE_FAILED, "UNREGISTER_SERVICE_FAILED"); - EVENT_NAMES.put(UNREGISTER_SERVICE_SUCCEEDED, "UNREGISTER_SERVICE_SUCCEEDED"); - EVENT_NAMES.put(RESOLVE_SERVICE, "RESOLVE_SERVICE"); - EVENT_NAMES.put(RESOLVE_SERVICE_FAILED, "RESOLVE_SERVICE_FAILED"); - EVENT_NAMES.put(RESOLVE_SERVICE_SUCCEEDED, "RESOLVE_SERVICE_SUCCEEDED"); - EVENT_NAMES.put(DAEMON_CLEANUP, "DAEMON_CLEANUP"); - EVENT_NAMES.put(DAEMON_STARTUP, "DAEMON_STARTUP"); - EVENT_NAMES.put(ENABLE, "ENABLE"); - EVENT_NAMES.put(DISABLE, "DISABLE"); - EVENT_NAMES.put(NATIVE_DAEMON_EVENT, "NATIVE_DAEMON_EVENT"); - } - - /** @hide */ - public static String nameOf(int event) { - String name = EVENT_NAMES.get(event); - if (name == null) { - return Integer.toString(event); - } - return name; - } - - private static final int FIRST_LISTENER_KEY = 1; - - private final INsdServiceConnector mService; - private final Context mContext; - - private int mListenerKey = FIRST_LISTENER_KEY; - @GuardedBy("mMapLock") - private final SparseArray mListenerMap = new SparseArray(); - @GuardedBy("mMapLock") - private final SparseArray mServiceMap = new SparseArray<>(); - @GuardedBy("mMapLock") - private final SparseArray mExecutorMap = new SparseArray<>(); - private final Object mMapLock = new Object(); - // Map of listener key sent by client -> per-network discovery tracker - @GuardedBy("mPerNetworkDiscoveryMap") - private final ArrayMap - mPerNetworkDiscoveryMap = new ArrayMap<>(); - - private final ServiceHandler mHandler; - - private class PerNetworkDiscoveryTracker { - final String mServiceType; - final int mProtocolType; - final DiscoveryListener mBaseListener; - final Executor mBaseExecutor; - final ArrayMap mPerNetworkListeners = - new ArrayMap<>(); - - final NetworkCallback mNetworkCb = new NetworkCallback() { - @Override - public void onAvailable(@NonNull Network network) { - final DelegatingDiscoveryListener wrappedListener = new DelegatingDiscoveryListener( - network, mBaseListener); - mPerNetworkListeners.put(network, wrappedListener); - discoverServices(mServiceType, mProtocolType, network, mBaseExecutor, - wrappedListener); - } - - @Override - public void onLost(@NonNull Network network) { - final DelegatingDiscoveryListener listener = mPerNetworkListeners.get(network); - if (listener == null) return; - listener.notifyAllServicesLost(); - // Listener will be removed from map in discovery stopped callback - stopServiceDiscovery(listener); - } - }; - - // Accessed from mHandler - private boolean mStopRequested; - - public void start(@NonNull NetworkRequest request) { - final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); - cm.registerNetworkCallback(request, mNetworkCb, mHandler); - mHandler.post(() -> mBaseListener.onDiscoveryStarted(mServiceType)); - } - - /** - * Stop discovery on all networks tracked by this class. - * - * This will request all underlying listeners to stop, and the last one to stop will call - * onDiscoveryStopped or onStopDiscoveryFailed. - * - * Must be called on the handler thread. - */ - public void requestStop() { - mHandler.post(() -> { - mStopRequested = true; - final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); - cm.unregisterNetworkCallback(mNetworkCb); - if (mPerNetworkListeners.size() == 0) { - mBaseListener.onDiscoveryStopped(mServiceType); - return; - } - for (int i = 0; i < mPerNetworkListeners.size(); i++) { - final DelegatingDiscoveryListener listener = mPerNetworkListeners.valueAt(i); - stopServiceDiscovery(listener); - } - }); - } - - private PerNetworkDiscoveryTracker(String serviceType, int protocolType, - Executor baseExecutor, DiscoveryListener baseListener) { - mServiceType = serviceType; - mProtocolType = protocolType; - mBaseExecutor = baseExecutor; - mBaseListener = baseListener; - } - - /** - * Subset of NsdServiceInfo that is tracked to generate service lost notifications when a - * network is lost. - * - * Service lost notifications only contain service name, type and network, so only track - * that information (Network is known from the listener). This also implements - * equals/hashCode for usage in maps. - */ - private class TrackedNsdInfo { - private final String mServiceName; - private final String mServiceType; - TrackedNsdInfo(NsdServiceInfo info) { - mServiceName = info.getServiceName(); - mServiceType = info.getServiceType(); - } - - @Override - public int hashCode() { - return Objects.hash(mServiceName, mServiceType); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof TrackedNsdInfo)) return false; - final TrackedNsdInfo other = (TrackedNsdInfo) obj; - return Objects.equals(mServiceName, other.mServiceName) - && Objects.equals(mServiceType, other.mServiceType); - } - } - - private class DelegatingDiscoveryListener implements DiscoveryListener { - private final Network mNetwork; - private final DiscoveryListener mWrapped; - private final ArraySet mFoundInfo = new ArraySet<>(); - - private DelegatingDiscoveryListener(Network network, DiscoveryListener listener) { - mNetwork = network; - mWrapped = listener; - } - - void notifyAllServicesLost() { - for (int i = 0; i < mFoundInfo.size(); i++) { - final TrackedNsdInfo trackedInfo = mFoundInfo.valueAt(i); - final NsdServiceInfo serviceInfo = new NsdServiceInfo( - trackedInfo.mServiceName, trackedInfo.mServiceType); - serviceInfo.setNetwork(mNetwork); - mWrapped.onServiceLost(serviceInfo); - } - } - - @Override - public void onStartDiscoveryFailed(String serviceType, int errorCode) { - // The delegated listener is used when NsdManager takes care of starting/stopping - // discovery on multiple networks. Failure to start on one network is not a global - // failure to be reported up, as other networks may succeed: just log. - Log.e(TAG, "Failed to start discovery for " + serviceType + " on " + mNetwork - + " with code " + errorCode); - mPerNetworkListeners.remove(mNetwork); - } - - @Override - public void onDiscoveryStarted(String serviceType) { - // Wrapped listener was called upon registration, it is not called for discovery - // on each network - } - - @Override - public void onStopDiscoveryFailed(String serviceType, int errorCode) { - Log.e(TAG, "Failed to stop discovery for " + serviceType + " on " + mNetwork - + " with code " + errorCode); - mPerNetworkListeners.remove(mNetwork); - if (mStopRequested && mPerNetworkListeners.size() == 0) { - // Do not report onStopDiscoveryFailed when some underlying listeners failed: - // this does not mean that all listeners did, and onStopDiscoveryFailed is not - // actionable anyway. Just report that discovery stopped. - mWrapped.onDiscoveryStopped(serviceType); - } - } - - @Override - public void onDiscoveryStopped(String serviceType) { - mPerNetworkListeners.remove(mNetwork); - if (mStopRequested && mPerNetworkListeners.size() == 0) { - mWrapped.onDiscoveryStopped(serviceType); - } - } - - @Override - public void onServiceFound(NsdServiceInfo serviceInfo) { - mFoundInfo.add(new TrackedNsdInfo(serviceInfo)); - mWrapped.onServiceFound(serviceInfo); - } - - @Override - public void onServiceLost(NsdServiceInfo serviceInfo) { - mFoundInfo.remove(new TrackedNsdInfo(serviceInfo)); - mWrapped.onServiceLost(serviceInfo); - } - } - } - - /** - * Create a new Nsd instance. Applications use - * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve - * {@link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}. - * @param service the Binder interface - * @hide - hide this because it takes in a parameter of type INsdManager, which - * is a system private class. - */ - public NsdManager(Context context, INsdManager service) { - mContext = context; - - HandlerThread t = new HandlerThread("NsdManager"); - t.start(); - mHandler = new ServiceHandler(t.getLooper()); - - try { - mService = service.connect(new NsdCallbackImpl(mHandler)); - } catch (RemoteException e) { - throw new RuntimeException("Failed to connect to NsdService"); - } - - // Only proactively start the daemon if the target SDK < S, otherwise the internal service - // would automatically start/stop the native daemon as needed. - if (!CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) { - try { - mService.startDaemon(); - } catch (RemoteException e) { - Log.e(TAG, "Failed to proactively start daemon"); - // Continue: the daemon can still be started on-demand later - } - } - } - - private static class NsdCallbackImpl extends INsdManagerCallback.Stub { - private final Handler mServHandler; - - NsdCallbackImpl(Handler serviceHandler) { - mServHandler = serviceHandler; - } - - private void sendInfo(int message, int listenerKey, NsdServiceInfo info) { - mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey, info)); - } - - private void sendError(int message, int listenerKey, int error) { - mServHandler.sendMessage(mServHandler.obtainMessage(message, error, listenerKey)); - } - - private void sendNoArg(int message, int listenerKey) { - mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey)); - } - - @Override - public void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) { - sendInfo(DISCOVER_SERVICES_STARTED, listenerKey, info); - } - - @Override - public void onDiscoverServicesFailed(int listenerKey, int error) { - sendError(DISCOVER_SERVICES_FAILED, listenerKey, error); - } - - @Override - public void onServiceFound(int listenerKey, NsdServiceInfo info) { - sendInfo(SERVICE_FOUND, listenerKey, info); - } - - @Override - public void onServiceLost(int listenerKey, NsdServiceInfo info) { - sendInfo(SERVICE_LOST, listenerKey, info); - } - - @Override - public void onStopDiscoveryFailed(int listenerKey, int error) { - sendError(STOP_DISCOVERY_FAILED, listenerKey, error); - } - - @Override - public void onStopDiscoverySucceeded(int listenerKey) { - sendNoArg(STOP_DISCOVERY_SUCCEEDED, listenerKey); - } - - @Override - public void onRegisterServiceFailed(int listenerKey, int error) { - sendError(REGISTER_SERVICE_FAILED, listenerKey, error); - } - - @Override - public void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) { - sendInfo(REGISTER_SERVICE_SUCCEEDED, listenerKey, info); - } - - @Override - public void onUnregisterServiceFailed(int listenerKey, int error) { - sendError(UNREGISTER_SERVICE_FAILED, listenerKey, error); - } - - @Override - public void onUnregisterServiceSucceeded(int listenerKey) { - sendNoArg(UNREGISTER_SERVICE_SUCCEEDED, listenerKey); - } - - @Override - public void onResolveServiceFailed(int listenerKey, int error) { - sendError(RESOLVE_SERVICE_FAILED, listenerKey, error); - } - - @Override - public void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) { - sendInfo(RESOLVE_SERVICE_SUCCEEDED, listenerKey, info); - } - } - - /** - * Failures are passed with {@link RegistrationListener#onRegistrationFailed}, - * {@link RegistrationListener#onUnregistrationFailed}, - * {@link DiscoveryListener#onStartDiscoveryFailed}, - * {@link DiscoveryListener#onStopDiscoveryFailed} or {@link ResolveListener#onResolveFailed}. - * - * Indicates that the operation failed due to an internal error. - */ - public static final int FAILURE_INTERNAL_ERROR = 0; - - /** - * Indicates that the operation failed because it is already active. - */ - public static final int FAILURE_ALREADY_ACTIVE = 3; - - /** - * Indicates that the operation failed because the maximum outstanding - * requests from the applications have reached. - */ - public static final int FAILURE_MAX_LIMIT = 4; - - /** Interface for callback invocation for service discovery */ - public interface DiscoveryListener { - - public void onStartDiscoveryFailed(String serviceType, int errorCode); - - public void onStopDiscoveryFailed(String serviceType, int errorCode); - - public void onDiscoveryStarted(String serviceType); - - public void onDiscoveryStopped(String serviceType); - - public void onServiceFound(NsdServiceInfo serviceInfo); - - public void onServiceLost(NsdServiceInfo serviceInfo); - } - - /** Interface for callback invocation for service registration */ - public interface RegistrationListener { - - public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode); - - public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode); - - public void onServiceRegistered(NsdServiceInfo serviceInfo); - - public void onServiceUnregistered(NsdServiceInfo serviceInfo); - } - - /** Interface for callback invocation for service resolution */ - public interface ResolveListener { - - public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode); - - public void onServiceResolved(NsdServiceInfo serviceInfo); - } - - @VisibleForTesting - class ServiceHandler extends Handler { - ServiceHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message message) { - final int what = message.what; - final int key = message.arg2; - final Object listener; - final NsdServiceInfo ns; - final Executor executor; - synchronized (mMapLock) { - listener = mListenerMap.get(key); - ns = mServiceMap.get(key); - executor = mExecutorMap.get(key); - } - if (listener == null) { - Log.d(TAG, "Stale key " + message.arg2); - return; - } - if (DBG) { - Log.d(TAG, "received " + nameOf(what) + " for key " + key + ", service " + ns); - } - switch (what) { - case DISCOVER_SERVICES_STARTED: - final String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); - executor.execute(() -> ((DiscoveryListener) listener).onDiscoveryStarted(s)); - break; - case DISCOVER_SERVICES_FAILED: - removeListener(key); - executor.execute(() -> ((DiscoveryListener) listener).onStartDiscoveryFailed( - getNsdServiceInfoType(ns), message.arg1)); - break; - case SERVICE_FOUND: - executor.execute(() -> ((DiscoveryListener) listener).onServiceFound( - (NsdServiceInfo) message.obj)); - break; - case SERVICE_LOST: - executor.execute(() -> ((DiscoveryListener) listener).onServiceLost( - (NsdServiceInfo) message.obj)); - break; - case STOP_DISCOVERY_FAILED: - // TODO: failure to stop discovery should be internal and retried internally, as - // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED - removeListener(key); - executor.execute(() -> ((DiscoveryListener) listener).onStopDiscoveryFailed( - getNsdServiceInfoType(ns), message.arg1)); - break; - case STOP_DISCOVERY_SUCCEEDED: - removeListener(key); - executor.execute(() -> ((DiscoveryListener) listener).onDiscoveryStopped( - getNsdServiceInfoType(ns))); - break; - case REGISTER_SERVICE_FAILED: - removeListener(key); - executor.execute(() -> ((RegistrationListener) listener).onRegistrationFailed( - ns, message.arg1)); - break; - case REGISTER_SERVICE_SUCCEEDED: - executor.execute(() -> ((RegistrationListener) listener).onServiceRegistered( - (NsdServiceInfo) message.obj)); - break; - case UNREGISTER_SERVICE_FAILED: - removeListener(key); - executor.execute(() -> ((RegistrationListener) listener).onUnregistrationFailed( - ns, message.arg1)); - break; - case UNREGISTER_SERVICE_SUCCEEDED: - // TODO: do not unregister listener until service is unregistered, or provide - // alternative way for unregistering ? - removeListener(message.arg2); - executor.execute(() -> ((RegistrationListener) listener).onServiceUnregistered( - ns)); - break; - case RESOLVE_SERVICE_FAILED: - removeListener(key); - executor.execute(() -> ((ResolveListener) listener).onResolveFailed( - ns, message.arg1)); - break; - case RESOLVE_SERVICE_SUCCEEDED: - removeListener(key); - executor.execute(() -> ((ResolveListener) listener).onServiceResolved( - (NsdServiceInfo) message.obj)); - break; - default: - Log.d(TAG, "Ignored " + message); - break; - } - } - } - - private int nextListenerKey() { - // Ensure mListenerKey >= FIRST_LISTENER_KEY; - mListenerKey = Math.max(FIRST_LISTENER_KEY, mListenerKey + 1); - return mListenerKey; - } - - // Assert that the listener is not in the map, then add it and returns its key - private int putListener(Object listener, Executor e, NsdServiceInfo s) { - checkListener(listener); - final int key; - synchronized (mMapLock) { - int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex != -1) { - throw new IllegalArgumentException("listener already in use"); - } - key = nextListenerKey(); - mListenerMap.put(key, listener); - mServiceMap.put(key, s); - mExecutorMap.put(key, e); - } - return key; - } - - private void removeListener(int key) { - synchronized (mMapLock) { - mListenerMap.remove(key); - mServiceMap.remove(key); - mExecutorMap.remove(key); - } - } - - private int getListenerKey(Object listener) { - checkListener(listener); - synchronized (mMapLock) { - int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex == -1) { - throw new IllegalArgumentException("listener not registered"); - } - return mListenerMap.keyAt(valueIndex); - } - } - - private static String getNsdServiceInfoType(NsdServiceInfo s) { - if (s == null) return "?"; - return s.getServiceType(); - } - - /** - * Register a service to be discovered by other services. - * - *

The function call immediately returns after sending a request to register service - * to the framework. The application is notified of a successful registration - * through the callback {@link RegistrationListener#onServiceRegistered} or a failure - * through {@link RegistrationListener#onRegistrationFailed}. - * - *

The application should call {@link #unregisterService} when the service - * registration is no longer required, and/or whenever the application is stopped. - * - * @param serviceInfo The service being registered - * @param protocolType The service discovery protocol - * @param listener The listener notifies of a successful registration and is used to - * unregister this service through a call on {@link #unregisterService}. Cannot be null. - * Cannot be in use for an active service registration. - */ - public void registerService(NsdServiceInfo serviceInfo, int protocolType, - RegistrationListener listener) { - registerService(serviceInfo, protocolType, Runnable::run, listener); - } - - /** - * Register a service to be discovered by other services. - * - *

The function call immediately returns after sending a request to register service - * to the framework. The application is notified of a successful registration - * through the callback {@link RegistrationListener#onServiceRegistered} or a failure - * through {@link RegistrationListener#onRegistrationFailed}. - * - *

The application should call {@link #unregisterService} when the service - * registration is no longer required, and/or whenever the application is stopped. - * @param serviceInfo The service being registered - * @param protocolType The service discovery protocol - * @param executor Executor to run listener callbacks with - * @param listener The listener notifies of a successful registration and is used to - * unregister this service through a call on {@link #unregisterService}. Cannot be null. - */ - public void registerService(@NonNull NsdServiceInfo serviceInfo, int protocolType, - @NonNull Executor executor, @NonNull RegistrationListener listener) { - if (serviceInfo.getPort() <= 0) { - throw new IllegalArgumentException("Invalid port number"); - } - checkServiceInfo(serviceInfo); - checkProtocol(protocolType); - int key = putListener(listener, executor, serviceInfo); - try { - mService.registerService(key, serviceInfo); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - /** - * Unregister a service registered through {@link #registerService}. A successful - * unregister is notified to the application with a call to - * {@link RegistrationListener#onServiceUnregistered}. - * - * @param listener This should be the listener object that was passed to - * {@link #registerService}. It identifies the service that should be unregistered - * and notifies of a successful or unsuccessful unregistration via the listener - * callbacks. In API versions 20 and above, the listener object may be used for - * another service registration once the callback has been called. In API versions <= 19, - * there is no entirely reliable way to know when a listener may be re-used, and a new - * listener should be created for each service registration request. - */ - public void unregisterService(RegistrationListener listener) { - int id = getListenerKey(listener); - try { - mService.unregisterService(id); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - /** - * Initiate service discovery to browse for instances of a service type. Service discovery - * consumes network bandwidth and will continue until the application calls - * {@link #stopServiceDiscovery}. - * - *

The function call immediately returns after sending a request to start service - * discovery to the framework. The application is notified of a success to initiate - * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure - * through {@link DiscoveryListener#onStartDiscoveryFailed}. - * - *

Upon successful start, application is notified when a service is found with - * {@link DiscoveryListener#onServiceFound} or when a service is lost with - * {@link DiscoveryListener#onServiceLost}. - * - *

Upon failure to start, service discovery is not active and application does - * not need to invoke {@link #stopServiceDiscovery} - * - *

The application should call {@link #stopServiceDiscovery} when discovery of this - * service type is no longer required, and/or whenever the application is paused or - * stopped. - * - * @param serviceType The service type being discovered. Examples include "_http._tcp" for - * http services or "_ipp._tcp" for printers - * @param protocolType The service discovery protocol - * @param listener The listener notifies of a successful discovery and is used - * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. - * Cannot be null. Cannot be in use for an active service discovery. - */ - public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { - discoverServices(serviceType, protocolType, (Network) null, Runnable::run, listener); - } - - /** - * Initiate service discovery to browse for instances of a service type. Service discovery - * consumes network bandwidth and will continue until the application calls - * {@link #stopServiceDiscovery}. - * - *

The function call immediately returns after sending a request to start service - * discovery to the framework. The application is notified of a success to initiate - * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure - * through {@link DiscoveryListener#onStartDiscoveryFailed}. - * - *

Upon successful start, application is notified when a service is found with - * {@link DiscoveryListener#onServiceFound} or when a service is lost with - * {@link DiscoveryListener#onServiceLost}. - * - *

Upon failure to start, service discovery is not active and application does - * not need to invoke {@link #stopServiceDiscovery} - * - *

The application should call {@link #stopServiceDiscovery} when discovery of this - * service type is no longer required, and/or whenever the application is paused or - * stopped. - * @param serviceType The service type being discovered. Examples include "_http._tcp" for - * http services or "_ipp._tcp" for printers - * @param protocolType The service discovery protocol - * @param network Network to discover services on, or null to discover on all available networks - * @param executor Executor to run listener callbacks with - * @param listener The listener notifies of a successful discovery and is used - * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. - */ - public void discoverServices(@NonNull String serviceType, int protocolType, - @Nullable Network network, @NonNull Executor executor, - @NonNull DiscoveryListener listener) { - if (TextUtils.isEmpty(serviceType)) { - throw new IllegalArgumentException("Service type cannot be empty"); - } - checkProtocol(protocolType); - - NsdServiceInfo s = new NsdServiceInfo(); - s.setServiceType(serviceType); - s.setNetwork(network); - - int key = putListener(listener, executor, s); - try { - mService.discoverServices(key, s); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - /** - * Initiate service discovery to browse for instances of a service type. Service discovery - * consumes network bandwidth and will continue until the application calls - * {@link #stopServiceDiscovery}. - * - *

The function call immediately returns after sending a request to start service - * discovery to the framework. The application is notified of a success to initiate - * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure - * through {@link DiscoveryListener#onStartDiscoveryFailed}. - * - *

Upon successful start, application is notified when a service is found with - * {@link DiscoveryListener#onServiceFound} or when a service is lost with - * {@link DiscoveryListener#onServiceLost}. - * - *

Upon failure to start, service discovery is not active and application does - * not need to invoke {@link #stopServiceDiscovery} - * - *

The application should call {@link #stopServiceDiscovery} when discovery of this - * service type is no longer required, and/or whenever the application is paused or - * stopped. - * - *

During discovery, new networks may connect or existing networks may disconnect - for - * example if wifi is reconnected. When a service was found on a network that disconnects, - * {@link DiscoveryListener#onServiceLost} will be called. If a new network connects that - * matches the {@link NetworkRequest}, {@link DiscoveryListener#onServiceFound} will be called - * for services found on that network. Applications that do not want to track networks - * themselves are encouraged to use this method instead of other overloads of - * {@code discoverServices}, as they will receive proper notifications when a service becomes - * available or unavailable due to network changes. - * @param serviceType The service type being discovered. Examples include "_http._tcp" for - * http services or "_ipp._tcp" for printers - * @param protocolType The service discovery protocol - * @param networkRequest Request specifying networks that should be considered when discovering - * @param executor Executor to run listener callbacks with - * @param listener The listener notifies of a successful discovery and is used - * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - public void discoverServices(@NonNull String serviceType, int protocolType, - @NonNull NetworkRequest networkRequest, @NonNull Executor executor, - @NonNull DiscoveryListener listener) { - if (TextUtils.isEmpty(serviceType)) { - throw new IllegalArgumentException("Service type cannot be empty"); - } - Objects.requireNonNull(networkRequest, "NetworkRequest cannot be null"); - checkProtocol(protocolType); - - NsdServiceInfo s = new NsdServiceInfo(); - s.setServiceType(serviceType); - - final int baseListenerKey = putListener(listener, executor, s); - - final PerNetworkDiscoveryTracker discoveryInfo = new PerNetworkDiscoveryTracker( - serviceType, protocolType, executor, listener); - - synchronized (mPerNetworkDiscoveryMap) { - mPerNetworkDiscoveryMap.put(baseListenerKey, discoveryInfo); - discoveryInfo.start(networkRequest); - } - } - - /** - * Stop service discovery initiated with {@link #discoverServices}. An active service - * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted} - * and it stays active until the application invokes a stop service discovery. A successful - * stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}. - * - *

Upon failure to stop service discovery, application is notified through - * {@link DiscoveryListener#onStopDiscoveryFailed}. - * - * @param listener This should be the listener object that was passed to {@link #discoverServices}. - * It identifies the discovery that should be stopped and notifies of a successful or - * unsuccessful stop. In API versions 20 and above, the listener object may be used for - * another service discovery once the callback has been called. In API versions <= 19, - * there is no entirely reliable way to know when a listener may be re-used, and a new - * listener should be created for each service discovery request. - */ - public void stopServiceDiscovery(DiscoveryListener listener) { - int id = getListenerKey(listener); - // If this is a PerNetworkDiscovery request, handle it as such - synchronized (mPerNetworkDiscoveryMap) { - final PerNetworkDiscoveryTracker info = mPerNetworkDiscoveryMap.get(id); - if (info != null) { - info.requestStop(); - return; - } - } - try { - mService.stopDiscovery(id); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - /** - * Resolve a discovered service. An application can resolve a service right before - * establishing a connection to fetch the IP and port details on which to setup - * the connection. - * - * @param serviceInfo service to be resolved - * @param listener to receive callback upon success or failure. Cannot be null. - * Cannot be in use for an active service resolution. - */ - public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { - resolveService(serviceInfo, Runnable::run, listener); - } - - /** - * Resolve a discovered service. An application can resolve a service right before - * establishing a connection to fetch the IP and port details on which to setup - * the connection. - * @param serviceInfo service to be resolved - * @param executor Executor to run listener callbacks with - * @param listener to receive callback upon success or failure. - */ - public void resolveService(@NonNull NsdServiceInfo serviceInfo, - @NonNull Executor executor, @NonNull ResolveListener listener) { - checkServiceInfo(serviceInfo); - int key = putListener(listener, executor, serviceInfo); - try { - mService.resolveService(key, serviceInfo); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); - } - } - - private static void checkListener(Object listener) { - Objects.requireNonNull(listener, "listener cannot be null"); - } - - private static void checkProtocol(int protocolType) { - if (protocolType != PROTOCOL_DNS_SD) { - throw new IllegalArgumentException("Unsupported protocol"); - } - } - - private static void checkServiceInfo(NsdServiceInfo serviceInfo) { - Objects.requireNonNull(serviceInfo, "NsdServiceInfo cannot be null"); - if (TextUtils.isEmpty(serviceInfo.getServiceName())) { - throw new IllegalArgumentException("Service name cannot be empty"); - } - if (TextUtils.isEmpty(serviceInfo.getServiceType())) { - throw new IllegalArgumentException("Service type cannot be empty"); - } - } -} diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java deleted file mode 100644 index 8506db1fbe012..0000000000000 --- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (C) 2012 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.nsd; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.net.Network; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.Base64; -import android.util.Log; - -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.Map; - -/** - * A class representing service information for network service discovery - * {@see NsdManager} - */ -public final class NsdServiceInfo implements Parcelable { - - private static final String TAG = "NsdServiceInfo"; - - private String mServiceName; - - private String mServiceType; - - private final ArrayMap mTxtRecord = new ArrayMap<>(); - - private InetAddress mHost; - - private int mPort; - - @Nullable - private Network mNetwork; - - public NsdServiceInfo() { - } - - /** @hide */ - public NsdServiceInfo(String sn, String rt) { - mServiceName = sn; - mServiceType = rt; - } - - /** Get the service name */ - public String getServiceName() { - return mServiceName; - } - - /** Set the service name */ - public void setServiceName(String s) { - mServiceName = s; - } - - /** Get the service type */ - public String getServiceType() { - return mServiceType; - } - - /** Set the service type */ - public void setServiceType(String s) { - mServiceType = s; - } - - /** Get the host address. The host address is valid for a resolved service. */ - public InetAddress getHost() { - return mHost; - } - - /** Set the host address */ - public void setHost(InetAddress s) { - mHost = s; - } - - /** Get port number. The port number is valid for a resolved service. */ - public int getPort() { - return mPort; - } - - /** Set port number */ - public void setPort(int p) { - mPort = p; - } - - /** - * Unpack txt information from a base-64 encoded byte array. - * - * @param rawRecords The raw base64 encoded records string read from netd. - * - * @hide - */ - public void setTxtRecords(@NonNull String rawRecords) { - byte[] txtRecordsRawBytes = Base64.decode(rawRecords, Base64.DEFAULT); - - // There can be multiple TXT records after each other. Each record has to following format: - // - // byte type required meaning - // ------------------- ------------------- -------- ---------------------------------- - // 0 unsigned 8 bit yes size of record excluding this byte - // 1 - n ASCII but not '=' yes key - // n + 1 '=' optional separator of key and value - // n + 2 - record size uninterpreted bytes optional value - // - // Example legal records: - // [11, 'm', 'y', 'k', 'e', 'y', '=', 0x0, 0x4, 0x65, 0x7, 0xff] - // [17, 'm', 'y', 'K', 'e', 'y', 'W', 'i', 't', 'h', 'N', 'o', 'V', 'a', 'l', 'u', 'e', '='] - // [12, 'm', 'y', 'B', 'o', 'o', 'l', 'e', 'a', 'n', 'K', 'e', 'y'] - // - // Example corrupted records - // [3, =, 1, 2] <- key is empty - // [3, 0, =, 2] <- key contains non-ASCII character. We handle this by replacing the - // invalid characters instead of skipping the record. - // [30, 'a', =, 2] <- length exceeds total left over bytes in the TXT records array, we - // handle this by reducing the length of the record as needed. - int pos = 0; - while (pos < txtRecordsRawBytes.length) { - // recordLen is an unsigned 8 bit value - int recordLen = txtRecordsRawBytes[pos] & 0xff; - pos += 1; - - try { - if (recordLen == 0) { - throw new IllegalArgumentException("Zero sized txt record"); - } else if (pos + recordLen > txtRecordsRawBytes.length) { - Log.w(TAG, "Corrupt record length (pos = " + pos + "): " + recordLen); - recordLen = txtRecordsRawBytes.length - pos; - } - - // Decode key-value records - String key = null; - byte[] value = null; - int valueLen = 0; - for (int i = pos; i < pos + recordLen; i++) { - if (key == null) { - if (txtRecordsRawBytes[i] == '=') { - key = new String(txtRecordsRawBytes, pos, i - pos, - StandardCharsets.US_ASCII); - } - } else { - if (value == null) { - value = new byte[recordLen - key.length() - 1]; - } - value[valueLen] = txtRecordsRawBytes[i]; - valueLen++; - } - } - - // If '=' was not found we have a boolean record - if (key == null) { - key = new String(txtRecordsRawBytes, pos, recordLen, StandardCharsets.US_ASCII); - } - - if (TextUtils.isEmpty(key)) { - // Empty keys are not allowed (RFC6763 6.4) - throw new IllegalArgumentException("Invalid txt record (key is empty)"); - } - - if (getAttributes().containsKey(key)) { - // When we have a duplicate record, the later ones are ignored (RFC6763 6.4) - throw new IllegalArgumentException("Invalid txt record (duplicate key \"" + key + "\")"); - } - - setAttribute(key, value); - } catch (IllegalArgumentException e) { - Log.e(TAG, "While parsing txt records (pos = " + pos + "): " + e.getMessage()); - } - - pos += recordLen; - } - } - - /** @hide */ - @UnsupportedAppUsage - public void setAttribute(String key, byte[] value) { - if (TextUtils.isEmpty(key)) { - throw new IllegalArgumentException("Key cannot be empty"); - } - - // Key must be printable US-ASCII, excluding =. - for (int i = 0; i < key.length(); ++i) { - char character = key.charAt(i); - if (character < 0x20 || character > 0x7E) { - throw new IllegalArgumentException("Key strings must be printable US-ASCII"); - } else if (character == 0x3D) { - throw new IllegalArgumentException("Key strings must not include '='"); - } - } - - // Key length + value length must be < 255. - if (key.length() + (value == null ? 0 : value.length) >= 255) { - throw new IllegalArgumentException("Key length + value length must be < 255 bytes"); - } - - // Warn if key is > 9 characters, as recommended by RFC 6763 section 6.4. - if (key.length() > 9) { - Log.w(TAG, "Key lengths > 9 are discouraged: " + key); - } - - // Check against total TXT record size limits. - // Arbitrary 400 / 1300 byte limits taken from RFC 6763 section 6.2. - int txtRecordSize = getTxtRecordSize(); - int futureSize = txtRecordSize + key.length() + (value == null ? 0 : value.length) + 2; - if (futureSize > 1300) { - throw new IllegalArgumentException("Total length of attributes must be < 1300 bytes"); - } else if (futureSize > 400) { - Log.w(TAG, "Total length of all attributes exceeds 400 bytes; truncation may occur"); - } - - mTxtRecord.put(key, value); - } - - /** - * Add a service attribute as a key/value pair. - * - *

Service attributes are included as DNS-SD TXT record pairs. - * - *

The key must be US-ASCII printable characters, excluding the '=' character. Values may - * be UTF-8 strings or null. The total length of key + value must be less than 255 bytes. - * - *

Keys should be short, ideally no more than 9 characters, and unique per instance of - * {@link NsdServiceInfo}. Calling {@link #setAttribute} twice with the same key will overwrite - * first value. - */ - public void setAttribute(String key, String value) { - try { - setAttribute(key, value == null ? (byte []) null : value.getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException("Value must be UTF-8"); - } - } - - /** Remove an attribute by key */ - public void removeAttribute(String key) { - mTxtRecord.remove(key); - } - - /** - * Retrieve attributes as a map of String keys to byte[] values. The attributes map is only - * valid for a resolved service. - * - *

The returned map is unmodifiable; changes must be made through {@link #setAttribute} and - * {@link #removeAttribute}. - */ - public Map getAttributes() { - return Collections.unmodifiableMap(mTxtRecord); - } - - private int getTxtRecordSize() { - int txtRecordSize = 0; - for (Map.Entry entry : mTxtRecord.entrySet()) { - txtRecordSize += 2; // One for the length byte, one for the = between key and value. - txtRecordSize += entry.getKey().length(); - byte[] value = entry.getValue(); - txtRecordSize += value == null ? 0 : value.length; - } - return txtRecordSize; - } - - /** @hide */ - public @NonNull byte[] getTxtRecord() { - int txtRecordSize = getTxtRecordSize(); - if (txtRecordSize == 0) { - return new byte[]{}; - } - - byte[] txtRecord = new byte[txtRecordSize]; - int ptr = 0; - for (Map.Entry entry : mTxtRecord.entrySet()) { - String key = entry.getKey(); - byte[] value = entry.getValue(); - - // One byte to record the length of this key/value pair. - txtRecord[ptr++] = (byte) (key.length() + (value == null ? 0 : value.length) + 1); - - // The key, in US-ASCII. - // Note: use the StandardCharsets const here because it doesn't raise exceptions and we - // already know the key is ASCII at this point. - System.arraycopy(key.getBytes(StandardCharsets.US_ASCII), 0, txtRecord, ptr, - key.length()); - ptr += key.length(); - - // US-ASCII '=' character. - txtRecord[ptr++] = (byte)'='; - - // The value, as any raw bytes. - if (value != null) { - System.arraycopy(value, 0, txtRecord, ptr, value.length); - ptr += value.length; - } - } - return txtRecord; - } - - /** - * Get the network where the service can be found. - * - * This is never null if this {@link NsdServiceInfo} was obtained from - * {@link NsdManager#discoverServices} or {@link NsdManager#resolveService}. - */ - @Nullable - public Network getNetwork() { - return mNetwork; - } - - /** - * Set the network where the service can be found. - * @param network The network, or null to search for, or to announce, the service on all - * connected networks. - */ - public void setNetwork(@Nullable Network network) { - mNetwork = network; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("name: ").append(mServiceName) - .append(", type: ").append(mServiceType) - .append(", host: ").append(mHost) - .append(", port: ").append(mPort) - .append(", network: ").append(mNetwork); - - byte[] txtRecord = getTxtRecord(); - sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8)); - return sb.toString(); - } - - /** Implement the Parcelable interface */ - public int describeContents() { - return 0; - } - - /** Implement the Parcelable interface */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mServiceName); - dest.writeString(mServiceType); - if (mHost != null) { - dest.writeInt(1); - dest.writeByteArray(mHost.getAddress()); - } else { - dest.writeInt(0); - } - dest.writeInt(mPort); - - // TXT record key/value pairs. - dest.writeInt(mTxtRecord.size()); - for (String key : mTxtRecord.keySet()) { - byte[] value = mTxtRecord.get(key); - if (value != null) { - dest.writeInt(1); - dest.writeInt(value.length); - dest.writeByteArray(value); - } else { - dest.writeInt(0); - } - dest.writeString(key); - } - - dest.writeParcelable(mNetwork, 0); - } - - /** Implement the Parcelable interface */ - public static final @android.annotation.NonNull Creator CREATOR = - new Creator() { - public NsdServiceInfo createFromParcel(Parcel in) { - NsdServiceInfo info = new NsdServiceInfo(); - info.mServiceName = in.readString(); - info.mServiceType = in.readString(); - - if (in.readInt() == 1) { - try { - info.mHost = InetAddress.getByAddress(in.createByteArray()); - } catch (java.net.UnknownHostException e) {} - } - - info.mPort = in.readInt(); - - // TXT record key/value pairs. - int recordCount = in.readInt(); - for (int i = 0; i < recordCount; ++i) { - byte[] valueArray = null; - if (in.readInt() == 1) { - int valueLength = in.readInt(); - valueArray = new byte[valueLength]; - in.readByteArray(valueArray); - } - info.mTxtRecord.put(in.readString(), valueArray); - } - info.mNetwork = in.readParcelable(null, Network.class); - return info; - } - - public NsdServiceInfo[] newArray(int size) { - return new NsdServiceInfo[size]; - } - }; -} diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp deleted file mode 100644 index 4b799c599be91..0000000000000 --- a/packages/ConnectivityT/service/Android.bp +++ /dev/null @@ -1,156 +0,0 @@ -// -// Copyright (C) 2021 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 { - // See: http://go/android-license-faq - default_applicable_licenses: ["Android-Apache-2.0"], -} - -// NetworkStats related libraries. - -filegroup { - name: "services.connectivity-netstats-sources", - srcs: [ - "src/com/android/server/net/NetworkIdentity*.java", - "src/com/android/server/net/NetworkStats*.java", - "src/com/android/server/net/BpfInterfaceMapUpdater.java", - "src/com/android/server/net/InterfaceMapValue.java", - "src/com/android/server/net/CookieTagMapKey.java", - "src/com/android/server/net/CookieTagMapValue.java", - "src/com/android/server/net/StatsMapKey.java", - "src/com/android/server/net/StatsMapValue.java", - "src/com/android/server/net/UidStatsMapKey.java", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// For test code only. -filegroup { - name: "lib_networkStatsFactory_native", - srcs: [ - "jni/com_android_server_net_NetworkStatsFactory.cpp", - ], - path: "jni", - visibility: [ - "//packages/modules/Connectivity:__subpackages__", - ], -} - -filegroup { - name: "services.connectivity-netstats-jni-sources", - srcs: [ - "jni/com_android_server_net_NetworkStatsFactory.cpp", - "jni/com_android_server_net_NetworkStatsService.cpp", - ], - path: "jni", - visibility: [ - "//packages/modules/Connectivity:__subpackages__", - ], -} - -// Nsd related libraries. - -filegroup { - name: "services.connectivity-nsd-sources", - srcs: [ - "src/com/android/server/INativeDaemon*.java", - "src/com/android/server/NativeDaemon*.java", - "src/com/android/server/Nsd*.java", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// IpSec related libraries. - -filegroup { - name: "services.connectivity-ipsec-sources", - srcs: [ - "src/com/android/server/IpSecService.java", - ], - path: "src", - visibility: [ - "//visibility:private", - ], -} - -// Ethernet related libraries. - -filegroup { - name: "services.connectivity-ethernet-sources", - srcs: [ - "src/com/android/server/net/DelayedDiskWrite.java", - "src/com/android/server/net/IpConfigStore.java", - ], - path: "src", - visibility: [ - "//frameworks/opt/net/ethernet/tests", - ], -} - -// Connectivity-T common libraries. - -// TODO: remove this empty filegroup. -filegroup { - name: "services.connectivity-tiramisu-sources", - srcs: [], - path: "src", - visibility: ["//frameworks/base/services/core"], -} - -filegroup { - name: "services.connectivity-tiramisu-updatable-sources", - srcs: [ - ":services.connectivity-ethernet-sources", - ":services.connectivity-ipsec-sources", - ":services.connectivity-netstats-sources", - ":services.connectivity-nsd-sources", - ], - path: "src", - visibility: [ - "//packages/modules/Connectivity:__subpackages__", - ], -} - -cc_library_shared { - name: "libcom_android_net_module_util_jni", - min_sdk_version: "30", - cflags: [ - "-Wall", - "-Werror", - "-Wno-unused-parameter", - "-Wthread-safety", - ], - srcs: [ - "jni/onload.cpp", - ], - stl: "libc++_static", - static_libs: [ - "libnet_utils_device_common_bpfjni", - ], - shared_libs: [ - "liblog", - "libnativehelper", - ], - apex_available: [ - "//apex_available:platform", - ], -} diff --git a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp deleted file mode 100644 index 8b6526ff49f06..0000000000000 --- a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsFactory.cpp +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#define LOG_TAG "NetworkStats" - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include "android-base/unique_fd.h" -#include "bpf/BpfUtils.h" -#include "netdbpf/BpfNetworkStats.h" - -using android::bpf::parseBpfNetworkStatsDetail; -using android::bpf::stats_line; - -namespace android { - -static jclass gStringClass; - -static struct { - jfieldID size; - jfieldID capacity; - jfieldID iface; - jfieldID uid; - jfieldID set; - jfieldID tag; - jfieldID metered; - jfieldID roaming; - jfieldID defaultNetwork; - jfieldID rxBytes; - jfieldID rxPackets; - jfieldID txBytes; - jfieldID txPackets; - jfieldID operations; -} gNetworkStatsClassInfo; - -static jobjectArray get_string_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) -{ - if (!grow) { - jobjectArray array = (jobjectArray)env->GetObjectField(obj, field); - if (array != NULL) { - return array; - } - } - return env->NewObjectArray(size, gStringClass, NULL); -} - -static jintArray get_int_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) -{ - if (!grow) { - jintArray array = (jintArray)env->GetObjectField(obj, field); - if (array != NULL) { - return array; - } - } - return env->NewIntArray(size); -} - -static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) -{ - if (!grow) { - jlongArray array = (jlongArray)env->GetObjectField(obj, field); - if (array != NULL) { - return array; - } - } - return env->NewLongArray(size); -} - -static int legacyReadNetworkStatsDetail(std::vector* lines, - const std::vector& 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(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(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& lines) { - int size = lines.size(); - - bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity); - - ScopedLocalRef iface(env, get_string_array(env, stats, - gNetworkStatsClassInfo.iface, size, grow)); - if (iface.get() == NULL) return -1; - ScopedIntArrayRW uid(env, get_int_array(env, stats, - gNetworkStatsClassInfo.uid, size, grow)); - if (uid.get() == NULL) return -1; - ScopedIntArrayRW set(env, get_int_array(env, stats, - gNetworkStatsClassInfo.set, size, grow)); - if (set.get() == NULL) return -1; - ScopedIntArrayRW tag(env, get_int_array(env, stats, - gNetworkStatsClassInfo.tag, size, grow)); - if (tag.get() == NULL) return -1; - ScopedIntArrayRW metered(env, get_int_array(env, stats, - gNetworkStatsClassInfo.metered, size, grow)); - if (metered.get() == NULL) return -1; - ScopedIntArrayRW roaming(env, get_int_array(env, stats, - gNetworkStatsClassInfo.roaming, size, grow)); - if (roaming.get() == NULL) return -1; - ScopedIntArrayRW defaultNetwork(env, get_int_array(env, stats, - gNetworkStatsClassInfo.defaultNetwork, size, grow)); - if (defaultNetwork.get() == NULL) return -1; - ScopedLongArrayRW rxBytes(env, get_long_array(env, stats, - gNetworkStatsClassInfo.rxBytes, size, grow)); - if (rxBytes.get() == NULL) return -1; - ScopedLongArrayRW rxPackets(env, get_long_array(env, stats, - gNetworkStatsClassInfo.rxPackets, size, grow)); - if (rxPackets.get() == NULL) return -1; - ScopedLongArrayRW txBytes(env, get_long_array(env, stats, - gNetworkStatsClassInfo.txBytes, size, grow)); - if (txBytes.get() == NULL) return -1; - ScopedLongArrayRW txPackets(env, get_long_array(env, stats, - gNetworkStatsClassInfo.txPackets, size, grow)); - if (txPackets.get() == NULL) return -1; - ScopedLongArrayRW operations(env, get_long_array(env, stats, - gNetworkStatsClassInfo.operations, size, grow)); - if (operations.get() == NULL) return -1; - - for (int i = 0; i < size; i++) { - ScopedLocalRef ifaceString(env, env->NewStringUTF(lines[i].iface)); - env->SetObjectArrayElement(iface.get(), i, ifaceString.get()); - - uid[i] = lines[i].uid; - set[i] = lines[i].set; - tag[i] = lines[i].tag; - // Metered, roaming and defaultNetwork are populated in Java-land. - rxBytes[i] = lines[i].rxBytes; - rxPackets[i] = lines[i].rxPackets; - txBytes[i] = lines[i].txBytes; - txPackets[i] = lines[i].txPackets; - } - - env->SetIntField(stats, gNetworkStatsClassInfo.size, size); - if (grow) { - env->SetIntField(stats, gNetworkStatsClassInfo.capacity, size); - env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get()); - env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.defaultNetwork, - defaultNetwork.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray()); - } - return 0; -} - -static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, - jint limitUid, jobjectArray limitIfacesObj, jint limitTag, - jboolean useBpfStats) { - - std::vector limitIfaces; - if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { - int num = env->GetArrayLength(limitIfacesObj); - for (int i = 0; i < num; i++) { - jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); - ScopedUtfChars string8(env, string); - if (string8.c_str() != NULL) { - limitIfaces.push_back(std::string(string8.c_str())); - } - } - } - std::vector 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; - } - - return statsLinesToNetworkStats(env, clazz, stats, lines); -} - -static int readNetworkStatsDev(JNIEnv* env, jclass clazz, jobject stats) { - std::vector lines; - - if (parseBpfNetworkStatsDev(&lines) < 0) - return -1; - - return statsLinesToNetworkStats(env, clazz, stats, lines); -} - -static const JNINativeMethod gMethods[] = { - { "nativeReadNetworkStatsDetail", - "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I", - (void*) readNetworkStatsDetail }, - { "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I", - (void*) readNetworkStatsDev }, -}; - -int register_android_server_net_NetworkStatsFactory(JNIEnv* env) { - int err = jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsFactory", gMethods, - NELEM(gMethods)); - gStringClass = env->FindClass("java/lang/String"); - gStringClass = static_cast(env->NewGlobalRef(gStringClass)); - - jclass clazz = env->FindClass("android/net/NetworkStats"); - gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I"); - gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I"); - gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;"); - gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I"); - gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I"); - gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I"); - gNetworkStatsClassInfo.metered = env->GetFieldID(clazz, "metered", "[I"); - gNetworkStatsClassInfo.roaming = env->GetFieldID(clazz, "roaming", "[I"); - gNetworkStatsClassInfo.defaultNetwork = env->GetFieldID(clazz, "defaultNetwork", "[I"); - gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J"); - gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J"); - gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J"); - gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J"); - gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J"); - - return err; -} - -} diff --git a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp b/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp deleted file mode 100644 index 39cbaf716fc0a..0000000000000 --- a/packages/ConnectivityT/service/jni/com_android_server_net_NetworkStatsService.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#define LOG_TAG "NetworkStatsNative" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bpf/BpfUtils.h" -#include "netdbpf/BpfNetworkStats.h" - -using android::bpf::bpfGetUidStats; -using android::bpf::bpfGetIfaceStats; - -namespace android { - -// NOTE: keep these in sync with TrafficStats.java -static const uint64_t UNKNOWN = -1; - -enum StatsType { - RX_BYTES = 0, - RX_PACKETS = 1, - TX_BYTES = 2, - TX_PACKETS = 3, - TCP_RX_PACKETS = 4, - TCP_TX_PACKETS = 5 -}; - -static uint64_t getStatsType(Stats* stats, StatsType type) { - switch (type) { - case RX_BYTES: - return stats->rxBytes; - case RX_PACKETS: - return stats->rxPackets; - case TX_BYTES: - return stats->txBytes; - case TX_PACKETS: - return stats->txPackets; - case TCP_RX_PACKETS: - return stats->tcpRxPackets; - case TCP_TX_PACKETS: - return stats->tcpTxPackets; - default: - return UNKNOWN; - } -} - -static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) { - Stats stats = {}; - - if (bpfGetIfaceStats(NULL, &stats) == 0) { - return getStatsType(&stats, (StatsType) type); - } else { - return UNKNOWN; - } -} - -static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { - ScopedUtfChars iface8(env, iface); - if (iface8.c_str() == NULL) { - return UNKNOWN; - } - - Stats stats = {}; - - if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) { - return getStatsType(&stats, (StatsType) type); - } else { - return UNKNOWN; - } -} - -static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { - Stats stats = {}; - - if (bpfGetUidStats(uid, &stats) == 0) { - return getStatsType(&stats, (StatsType) type); - } else { - return UNKNOWN; - } -} - -static const JNINativeMethod gMethods[] = { - {"nativeGetTotalStat", "(I)J", (void*)getTotalStat}, - {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)getIfaceStat}, - {"nativeGetUidStat", "(II)J", (void*)getUidStat}, -}; - -int register_android_server_net_NetworkStatsService(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods, - NELEM(gMethods)); -} - -} diff --git a/packages/ConnectivityT/service/jni/onload.cpp b/packages/ConnectivityT/service/jni/onload.cpp deleted file mode 100644 index bca4697560956..0000000000000 --- a/packages/ConnectivityT/service/jni/onload.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2022 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. - */ - -#include -#include - -namespace android { - -int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name); - -extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { - JNIEnv *env; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { - ALOGE("GetEnv failed"); - return JNI_ERR; - } - - if (register_com_android_net_module_util_BpfMap(env, - "com/android/net/module/util/BpfMap") < 0) return JNI_ERR; - - return JNI_VERSION_1_6; -} - -}; - diff --git a/packages/ConnectivityT/service/src/com/android/server/INativeDaemonConnectorCallbacks.java b/packages/ConnectivityT/service/src/com/android/server/INativeDaemonConnectorCallbacks.java deleted file mode 100644 index 0cf9dcde012da..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/INativeDaemonConnectorCallbacks.java +++ /dev/null @@ -1,25 +0,0 @@ - -/* - * Copyright (C) 2007 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; - -interface INativeDaemonConnectorCallbacks { - - void onDaemonConnected(); - boolean onCheckHoldWakeLock(int code); - boolean onEvent(int code, String raw, String[] cooked); -} diff --git a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java deleted file mode 100644 index 4bc40eae44048..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java +++ /dev/null @@ -1,1878 +0,0 @@ -/* - * Copyright (C) 2017 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; - -import static android.Manifest.permission.DUMP; -import static android.net.IpSecManager.INVALID_RESOURCE_ID; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; -import static android.system.OsConstants.AF_UNSPEC; -import static android.system.OsConstants.EINVAL; -import static android.system.OsConstants.IPPROTO_UDP; -import static android.system.OsConstants.SOCK_DGRAM; - -import android.annotation.NonNull; -import android.app.AppOpsManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.IIpSecService; -import android.net.INetd; -import android.net.InetAddresses; -import android.net.IpSecAlgorithm; -import android.net.IpSecConfig; -import android.net.IpSecManager; -import android.net.IpSecSpiResponse; -import android.net.IpSecTransform; -import android.net.IpSecTransformResponse; -import android.net.IpSecTunnelInterfaceResponse; -import android.net.IpSecUdpEncapResponse; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.Network; -import android.net.TrafficStats; -import android.os.Binder; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.text.TextUtils; -import android.util.Log; -import android.util.Range; -import android.util.SparseArray; -import android.util.SparseBooleanArray; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; -import com.android.net.module.util.BinderUtils; -import com.android.net.module.util.NetdUtils; -import com.android.net.module.util.PermissionUtils; - -import libcore.io.IoUtils; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -/** - * A service to manage multiple clients that want to access the IpSec API. The service is - * responsible for maintaining a list of clients and managing the resources (and related quotas) - * that each of them own. - * - *

Synchronization in IpSecService is done on all entrypoints due to potential race conditions at - * the kernel/xfrm level. Further, this allows the simplifying assumption to be made that only one - * thread is ever running at a time. - * - * @hide - */ -public class IpSecService extends IIpSecService.Stub { - private static final String TAG = "IpSecService"; - private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); - private static final int[] ADDRESS_FAMILIES = - new int[] {OsConstants.AF_INET, OsConstants.AF_INET6}; - - private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms - private static final InetAddress INADDR_ANY; - - @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10; - - private final INetd mNetd; - - static { - try { - INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); - } catch (UnknownHostException e) { - throw new RuntimeException(e); - } - } - - static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved - static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer - - /* Binder context for this service */ - private final Context mContext; - private final Dependencies mDeps; - - /** - * The next non-repeating global ID for tracking resources between users, this service, and - * kernel data structures. Accessing this variable is not thread safe, so it is only read or - * modified within blocks synchronized on IpSecService.this. We want to avoid -1 - * (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it). - */ - @GuardedBy("IpSecService.this") - private int mNextResourceId = 1; - - /** - * Dependencies of IpSecService, for injection in tests. - */ - @VisibleForTesting - public static class Dependencies { - /** - * Get a reference to INetd. - */ - public INetd getNetdInstance(Context context) throws RemoteException { - final INetd netd = INetd.Stub.asInterface((IBinder) - context.getSystemService(Context.NETD_SERVICE)); - if (netd == null) { - throw new RemoteException("Failed to Get Netd Instance"); - } - return netd; - } - } - - final UidFdTagger mUidFdTagger; - - /** - * Interface for user-reference and kernel-resource cleanup. - * - *

This interface must be implemented for a resource to be reference counted. - */ - @VisibleForTesting - public interface IResource { - /** - * Invalidates a IResource object, ensuring it is invalid for the purposes of allocating new - * objects dependent on it. - * - *

Implementations of this method are expected to remove references to the IResource - * object from the IpSecService's tracking arrays. The removal from the arrays ensures that - * the resource is considered invalid for user access or allocation or use in other - * resources. - * - *

References to the IResource object may be held by other RefcountedResource objects, - * and as such, the underlying resources and quota may not be cleaned up. - */ - void invalidate() throws RemoteException; - - /** - * Releases underlying resources and related quotas. - * - *

Implementations of this method are expected to remove all system resources that are - * tracked by the IResource object. Due to other RefcountedResource objects potentially - * having references to the IResource object, freeUnderlyingResources may not always be - * called from releaseIfUnreferencedRecursively(). - */ - void freeUnderlyingResources() throws RemoteException; - } - - /** - * RefcountedResource manages references and dependencies in an exclusively acyclic graph. - * - *

RefcountedResource implements both explicit and implicit resource management. Creating a - * RefcountedResource object creates an explicit reference that must be freed by calling - * userRelease(). Additionally, adding this object as a child of another RefcountedResource - * object will add an implicit reference. - * - *

Resources are cleaned up when all references, both implicit and explicit, are released - * (ie, when userRelease() is called and when all parents have called releaseReference() on this - * object.) - */ - @VisibleForTesting - public class RefcountedResource implements IBinder.DeathRecipient { - private final T mResource; - private final List mChildren; - int mRefCount = 1; // starts at 1 for user's reference. - IBinder mBinder; - - RefcountedResource(T resource, IBinder binder, RefcountedResource... children) { - synchronized (IpSecService.this) { - this.mResource = resource; - this.mChildren = new ArrayList<>(children.length); - this.mBinder = binder; - - for (RefcountedResource child : children) { - mChildren.add(child); - child.mRefCount++; - } - - try { - mBinder.linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - e.rethrowFromSystemServer(); - } - } - } - - /** - * If the Binder object dies, this function is called to free the system resources that are - * being tracked by this record and to subsequently release this record for garbage - * collection - */ - @Override - public void binderDied() { - synchronized (IpSecService.this) { - try { - userRelease(); - } catch (Exception e) { - Log.e(TAG, "Failed to release resource: " + e); - } - } - } - - public T getResource() { - return mResource; - } - - /** - * Unlinks from binder and performs IpSecService resource cleanup (removes from resource - * arrays) - * - *

If this method has been previously called, the RefcountedResource's binder field will - * be null, and the method will return without performing the cleanup a second time. - * - *

Note that calling this function does not imply that kernel resources will be freed at - * this time, or that the related quota will be returned. Such actions will only be - * performed upon the reference count reaching zero. - */ - @GuardedBy("IpSecService.this") - public void userRelease() throws RemoteException { - // Prevent users from putting reference counts into a bad state by calling - // userRelease() multiple times. - if (mBinder == null) { - return; - } - - mBinder.unlinkToDeath(this, 0); - mBinder = null; - - mResource.invalidate(); - - releaseReference(); - } - - /** - * Removes a reference to this resource. If the resultant reference count is zero, the - * underlying resources are freed, and references to all child resources are also dropped - * recursively (resulting in them freeing their resources and children, etcetera) - * - *

This method also sets the reference count to an invalid value (-1) to signify that it - * has been fully released. Any subsequent calls to this method will result in an - * IllegalStateException being thrown due to resource already having been previously - * released - */ - @VisibleForTesting - @GuardedBy("IpSecService.this") - public void releaseReference() throws RemoteException { - mRefCount--; - - if (mRefCount > 0) { - return; - } else if (mRefCount < 0) { - throw new IllegalStateException( - "Invalid operation - resource has already been released."); - } - - // Cleanup own resources - mResource.freeUnderlyingResources(); - - // Cleanup child resources as needed - for (RefcountedResource child : mChildren) { - child.releaseReference(); - } - - // Enforce that resource cleanup can only be called once - // By decrementing the refcount (from 0 to -1), the next call will throw an - // IllegalStateException - it has already been released fully. - mRefCount--; - } - - @Override - public String toString() { - return new StringBuilder() - .append("{mResource=") - .append(mResource) - .append(", mRefCount=") - .append(mRefCount) - .append(", mChildren=") - .append(mChildren) - .append("}") - .toString(); - } - } - - /** - * Very simple counting class that looks much like a counting semaphore - * - *

This class is not thread-safe, and expects that that users of this class will ensure - * synchronization and thread safety by holding the IpSecService.this instance lock. - */ - @VisibleForTesting - static class ResourceTracker { - private final int mMax; - int mCurrent; - - ResourceTracker(int max) { - mMax = max; - mCurrent = 0; - } - - boolean isAvailable() { - return (mCurrent < mMax); - } - - void take() { - if (!isAvailable()) { - Log.wtf(TAG, "Too many resources allocated!"); - } - mCurrent++; - } - - void give() { - if (mCurrent <= 0) { - Log.wtf(TAG, "We've released this resource too many times"); - } - mCurrent--; - } - - @Override - public String toString() { - return new StringBuilder() - .append("{mCurrent=") - .append(mCurrent) - .append(", mMax=") - .append(mMax) - .append("}") - .toString(); - } - } - - @VisibleForTesting - static final class UserRecord { - /* Maximum number of each type of resource that a single UID may possess */ - - // Up to 4 active VPNs/IWLAN with potential soft handover. - public static final int MAX_NUM_TUNNEL_INTERFACES = 8; - public static final int MAX_NUM_ENCAP_SOCKETS = 16; - - // SPIs and Transforms are both cheap, and are 1:1 correlated. - public static final int MAX_NUM_TRANSFORMS = 64; - public static final int MAX_NUM_SPIS = 64; - - /** - * Store each of the OwnedResource types in an (thinly wrapped) sparse array for indexing - * and explicit (user) reference management. - * - *

These are stored in separate arrays to improve debuggability and dump output clarity. - * - *

Resources are removed from this array when the user releases their explicit reference - * by calling one of the releaseResource() methods. - */ - final RefcountedResourceArray mSpiRecords = - new RefcountedResourceArray<>(SpiRecord.class.getSimpleName()); - final RefcountedResourceArray mTransformRecords = - new RefcountedResourceArray<>(TransformRecord.class.getSimpleName()); - final RefcountedResourceArray mEncapSocketRecords = - new RefcountedResourceArray<>(EncapSocketRecord.class.getSimpleName()); - final RefcountedResourceArray mTunnelInterfaceRecords = - new RefcountedResourceArray<>(TunnelInterfaceRecord.class.getSimpleName()); - - /** - * Trackers for quotas for each of the OwnedResource types. - * - *

These trackers are separate from the resource arrays, since they are incremented and - * decremented at different points in time. Specifically, quota is only returned upon final - * resource deallocation (after all explicit and implicit references are released). Note - * that it is possible that calls to releaseResource() will not return the used quota if - * there are other resources that depend on (are parents of) the resource being released. - */ - final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS); - final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS); - final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); - final ResourceTracker mTunnelQuotaTracker = new ResourceTracker(MAX_NUM_TUNNEL_INTERFACES); - - void removeSpiRecord(int resourceId) { - mSpiRecords.remove(resourceId); - } - - void removeTransformRecord(int resourceId) { - mTransformRecords.remove(resourceId); - } - - void removeTunnelInterfaceRecord(int resourceId) { - mTunnelInterfaceRecords.remove(resourceId); - } - - void removeEncapSocketRecord(int resourceId) { - mEncapSocketRecords.remove(resourceId); - } - - @Override - public String toString() { - return new StringBuilder() - .append("{mSpiQuotaTracker=") - .append(mSpiQuotaTracker) - .append(", mTransformQuotaTracker=") - .append(mTransformQuotaTracker) - .append(", mSocketQuotaTracker=") - .append(mSocketQuotaTracker) - .append(", mTunnelQuotaTracker=") - .append(mTunnelQuotaTracker) - .append(", mSpiRecords=") - .append(mSpiRecords) - .append(", mTransformRecords=") - .append(mTransformRecords) - .append(", mEncapSocketRecords=") - .append(mEncapSocketRecords) - .append(", mTunnelInterfaceRecords=") - .append(mTunnelInterfaceRecords) - .append("}") - .toString(); - } - } - - /** - * This class is not thread-safe, and expects that that users of this class will ensure - * synchronization and thread safety by holding the IpSecService.this instance lock. - */ - @VisibleForTesting - static final class UserResourceTracker { - private final SparseArray mUserRecords = new SparseArray<>(); - - /** Lazy-initialization/getter that populates or retrieves the UserRecord as needed */ - public UserRecord getUserRecord(int uid) { - checkCallerUid(uid); - - UserRecord r = mUserRecords.get(uid); - if (r == null) { - r = new UserRecord(); - mUserRecords.put(uid, r); - } - return r; - } - - /** Safety method; guards against access of other user's UserRecords */ - private void checkCallerUid(int uid) { - if (uid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()) { - throw new SecurityException("Attempted access of unowned resources"); - } - } - - @Override - public String toString() { - return mUserRecords.toString(); - } - } - - @VisibleForTesting final UserResourceTracker mUserResourceTracker = new UserResourceTracker(); - - /** - * The OwnedResourceRecord class provides a facility to cleanly and reliably track system - * resources. It relies on a provided resourceId that should uniquely identify the kernel - * resource. To use this class, the user should implement the invalidate() and - * freeUnderlyingResources() methods that are responsible for cleaning up IpSecService resource - * tracking arrays and kernel resources, respectively. - * - *

This class associates kernel resources with the UID that owns and controls them. - */ - private abstract class OwnedResourceRecord implements IResource { - final int mPid; - final int mUid; - protected final int mResourceId; - - OwnedResourceRecord(int resourceId) { - super(); - if (resourceId == INVALID_RESOURCE_ID) { - throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID"); - } - mResourceId = resourceId; - mPid = Binder.getCallingPid(); - mUid = Binder.getCallingUid(); - - getResourceTracker().take(); - } - - @Override - public abstract void invalidate() throws RemoteException; - - /** Convenience method; retrieves the user resource record for the stored UID. */ - protected UserRecord getUserRecord() { - return mUserResourceTracker.getUserRecord(mUid); - } - - @Override - public abstract void freeUnderlyingResources() throws RemoteException; - - /** Get the resource tracker for this resource */ - protected abstract ResourceTracker getResourceTracker(); - - @Override - public String toString() { - return new StringBuilder() - .append("{mResourceId=") - .append(mResourceId) - .append(", pid=") - .append(mPid) - .append(", uid=") - .append(mUid) - .append("}") - .toString(); - } - }; - - /** - * Thin wrapper over SparseArray to ensure resources exist, and simplify generic typing. - * - *

RefcountedResourceArray prevents null insertions, and throws an IllegalArgumentException - * if a key is not found during a retrieval process. - */ - static class RefcountedResourceArray { - SparseArray> mArray = new SparseArray<>(); - private final String mTypeName; - - RefcountedResourceArray(String typeName) { - this.mTypeName = typeName; - } - - /** - * Accessor method to get inner resource object. - * - * @throws IllegalArgumentException if no resource with provided key is found. - */ - T getResourceOrThrow(int key) { - return getRefcountedResourceOrThrow(key).getResource(); - } - - /** - * Accessor method to get reference counting wrapper. - * - * @throws IllegalArgumentException if no resource with provided key is found. - */ - RefcountedResource getRefcountedResourceOrThrow(int key) { - RefcountedResource resource = mArray.get(key); - if (resource == null) { - throw new IllegalArgumentException( - String.format("No such %s found for given id: %d", mTypeName, key)); - } - - return resource; - } - - void put(int key, RefcountedResource obj) { - Objects.requireNonNull(obj, "Null resources cannot be added"); - mArray.put(key, obj); - } - - void remove(int key) { - mArray.remove(key); - } - - @Override - public String toString() { - return mArray.toString(); - } - } - - /** - * Tracks an SA in the kernel, and manages cleanup paths. Once a TransformRecord is - * created, the SpiRecord that originally tracked the SAs will reliquish the - * responsibility of freeing the underlying SA to this class via the mOwnedByTransform flag. - */ - private final class TransformRecord extends OwnedResourceRecord { - private final IpSecConfig mConfig; - private final SpiRecord mSpi; - private final EncapSocketRecord mSocket; - - TransformRecord( - int resourceId, IpSecConfig config, SpiRecord spi, EncapSocketRecord socket) { - super(resourceId); - mConfig = config; - mSpi = spi; - mSocket = socket; - - spi.setOwnedByTransform(); - } - - public IpSecConfig getConfig() { - return mConfig; - } - - public SpiRecord getSpiRecord() { - return mSpi; - } - - public EncapSocketRecord getSocketRecord() { - return mSocket; - } - - /** always guarded by IpSecService#this */ - @Override - public void freeUnderlyingResources() { - int spi = mSpi.getSpi(); - try { - mNetd.ipSecDeleteSecurityAssociation( - mUid, - mConfig.getSourceAddress(), - mConfig.getDestinationAddress(), - spi, - mConfig.getMarkValue(), - mConfig.getMarkMask(), - mConfig.getXfrmInterfaceId()); - } catch (RemoteException | ServiceSpecificException e) { - Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e); - } - - getResourceTracker().give(); - } - - @Override - public void invalidate() throws RemoteException { - getUserRecord().removeTransformRecord(mResourceId); - } - - @Override - protected ResourceTracker getResourceTracker() { - return getUserRecord().mTransformQuotaTracker; - } - - @Override - public String toString() { - StringBuilder strBuilder = new StringBuilder(); - strBuilder - .append("{super=") - .append(super.toString()) - .append(", mSocket=") - .append(mSocket) - .append(", mSpi.mResourceId=") - .append(mSpi.mResourceId) - .append(", mConfig=") - .append(mConfig) - .append("}"); - return strBuilder.toString(); - } - } - - /** - * Tracks a single SA in the kernel, and manages cleanup paths. Once used in a Transform, the - * responsibility for cleaning up underlying resources will be passed to the TransformRecord - * object - */ - private final class SpiRecord extends OwnedResourceRecord { - private final String mSourceAddress; - private final String mDestinationAddress; - private int mSpi; - - private boolean mOwnedByTransform = false; - - SpiRecord(int resourceId, String sourceAddress, - String destinationAddress, int spi) { - super(resourceId); - mSourceAddress = sourceAddress; - mDestinationAddress = destinationAddress; - mSpi = spi; - } - - /** always guarded by IpSecService#this */ - @Override - public void freeUnderlyingResources() { - try { - if (!mOwnedByTransform) { - mNetd.ipSecDeleteSecurityAssociation( - mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, - 0 /* mask */, 0 /* if_id */); - } - } catch (ServiceSpecificException | RemoteException e) { - Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); - } - - mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - - getResourceTracker().give(); - } - - public int getSpi() { - return mSpi; - } - - public String getDestinationAddress() { - return mDestinationAddress; - } - - public void setOwnedByTransform() { - if (mOwnedByTransform) { - // Programming error - throw new IllegalStateException("Cannot own an SPI twice!"); - } - - mOwnedByTransform = true; - } - - public boolean getOwnedByTransform() { - return mOwnedByTransform; - } - - @Override - public void invalidate() throws RemoteException { - getUserRecord().removeSpiRecord(mResourceId); - } - - @Override - protected ResourceTracker getResourceTracker() { - return getUserRecord().mSpiQuotaTracker; - } - - @Override - public String toString() { - StringBuilder strBuilder = new StringBuilder(); - strBuilder - .append("{super=") - .append(super.toString()) - .append(", mSpi=") - .append(mSpi) - .append(", mSourceAddress=") - .append(mSourceAddress) - .append(", mDestinationAddress=") - .append(mDestinationAddress) - .append(", mOwnedByTransform=") - .append(mOwnedByTransform) - .append("}"); - return strBuilder.toString(); - } - } - - private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray(); - final Range mNetIdRange = ConnectivityManager.getIpSecNetIdRange(); - private int mNextTunnelNetId = mNetIdRange.getLower(); - - /** - * Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces - * - *

This method should only be called from Binder threads. Do not call this from within the - * system server as it will crash the system on failure. - * - * @return an integer key within the netId range, if successful - * @throws IllegalStateException if unsuccessful (all netId are currently reserved) - */ - @VisibleForTesting - int reserveNetId() { - final int range = mNetIdRange.getUpper() - mNetIdRange.getLower() + 1; - synchronized (mTunnelNetIds) { - for (int i = 0; i < range; i++) { - final int netId = mNextTunnelNetId; - if (++mNextTunnelNetId > mNetIdRange.getUpper()) { - mNextTunnelNetId = mNetIdRange.getLower(); - } - if (!mTunnelNetIds.get(netId)) { - mTunnelNetIds.put(netId, true); - return netId; - } - } - } - throw new IllegalStateException("No free netIds to allocate"); - } - - @VisibleForTesting - void releaseNetId(int netId) { - synchronized (mTunnelNetIds) { - mTunnelNetIds.delete(netId); - } - } - - /** - * Tracks an tunnel interface, and manages cleanup paths. - * - *

This class is not thread-safe, and expects that that users of this class will ensure - * synchronization and thread safety by holding the IpSecService.this instance lock - */ - @VisibleForTesting - final class TunnelInterfaceRecord extends OwnedResourceRecord { - private final String mInterfaceName; - - // outer addresses - private final String mLocalAddress; - private final String mRemoteAddress; - - private final int mIkey; - private final int mOkey; - - private final int mIfId; - - private Network mUnderlyingNetwork; - - TunnelInterfaceRecord( - int resourceId, - String interfaceName, - Network underlyingNetwork, - String localAddr, - String remoteAddr, - int ikey, - int okey, - int intfId) { - super(resourceId); - - mInterfaceName = interfaceName; - mUnderlyingNetwork = underlyingNetwork; - mLocalAddress = localAddr; - mRemoteAddress = remoteAddr; - mIkey = ikey; - mOkey = okey; - mIfId = intfId; - } - - /** always guarded by IpSecService#this */ - @Override - public void freeUnderlyingResources() { - // Calls to netd - // Teardown VTI - // Delete global policies - try { - mNetd.ipSecRemoveTunnelInterface(mInterfaceName); - - for (int selAddrFamily : ADDRESS_FAMILIES) { - mNetd.ipSecDeleteSecurityPolicy( - mUid, - selAddrFamily, - IpSecManager.DIRECTION_OUT, - mOkey, - 0xffffffff, - mIfId); - mNetd.ipSecDeleteSecurityPolicy( - mUid, - selAddrFamily, - IpSecManager.DIRECTION_IN, - mIkey, - 0xffffffff, - mIfId); - } - } catch (ServiceSpecificException | RemoteException e) { - Log.e( - TAG, - "Failed to delete VTI with interface name: " - + mInterfaceName - + " and id: " - + mResourceId, e); - } - - getResourceTracker().give(); - releaseNetId(mIkey); - releaseNetId(mOkey); - } - - @GuardedBy("IpSecService.this") - public void setUnderlyingNetwork(Network underlyingNetwork) { - // When #applyTunnelModeTransform is called, this new underlying network will be used to - // update the output mark of the input transform. - mUnderlyingNetwork = underlyingNetwork; - } - - @GuardedBy("IpSecService.this") - public Network getUnderlyingNetwork() { - return mUnderlyingNetwork; - } - - public String getInterfaceName() { - return mInterfaceName; - } - - /** Returns the local, outer address for the tunnelInterface */ - public String getLocalAddress() { - return mLocalAddress; - } - - /** Returns the remote, outer address for the tunnelInterface */ - public String getRemoteAddress() { - return mRemoteAddress; - } - - public int getIkey() { - return mIkey; - } - - public int getOkey() { - return mOkey; - } - - public int getIfId() { - return mIfId; - } - - @Override - protected ResourceTracker getResourceTracker() { - return getUserRecord().mTunnelQuotaTracker; - } - - @Override - public void invalidate() { - getUserRecord().removeTunnelInterfaceRecord(mResourceId); - } - - @Override - public String toString() { - return new StringBuilder() - .append("{super=") - .append(super.toString()) - .append(", mInterfaceName=") - .append(mInterfaceName) - .append(", mUnderlyingNetwork=") - .append(mUnderlyingNetwork) - .append(", mLocalAddress=") - .append(mLocalAddress) - .append(", mRemoteAddress=") - .append(mRemoteAddress) - .append(", mIkey=") - .append(mIkey) - .append(", mOkey=") - .append(mOkey) - .append("}") - .toString(); - } - } - - /** - * Tracks a UDP encap socket, and manages cleanup paths - * - *

While this class does not manage non-kernel resources, race conditions around socket - * binding require that the service creates the encap socket, binds it and applies the socket - * policy before handing it to a user. - */ - private final class EncapSocketRecord extends OwnedResourceRecord { - private FileDescriptor mSocket; - private final int mPort; - - EncapSocketRecord(int resourceId, FileDescriptor socket, int port) { - super(resourceId); - mSocket = socket; - mPort = port; - } - - /** always guarded by IpSecService#this */ - @Override - public void freeUnderlyingResources() { - Log.d(TAG, "Closing port " + mPort); - IoUtils.closeQuietly(mSocket); - mSocket = null; - - getResourceTracker().give(); - } - - public int getPort() { - return mPort; - } - - public FileDescriptor getFileDescriptor() { - return mSocket; - } - - @Override - protected ResourceTracker getResourceTracker() { - return getUserRecord().mSocketQuotaTracker; - } - - @Override - public void invalidate() { - getUserRecord().removeEncapSocketRecord(mResourceId); - } - - @Override - public String toString() { - return new StringBuilder() - .append("{super=") - .append(super.toString()) - .append(", mSocket=") - .append(mSocket) - .append(", mPort=") - .append(mPort) - .append("}") - .toString(); - } - } - - /** - * Constructs a new IpSecService instance - * - * @param context Binder context for this service - */ - public IpSecService(Context context) { - this(context, new Dependencies()); - } - - @NonNull - private AppOpsManager getAppOpsManager() { - AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); - if (appOps == null) throw new RuntimeException("System Server couldn't get AppOps"); - return appOps; - } - - /** @hide */ - @VisibleForTesting - public IpSecService(Context context, Dependencies deps) { - this( - context, - deps, - (fd, uid) -> { - try { - TrafficStats.setThreadStatsUid(uid); - TrafficStats.tagFileDescriptor(fd); - } finally { - TrafficStats.clearThreadStatsUid(); - } - }); - } - - /** @hide */ - @VisibleForTesting - public IpSecService(Context context, Dependencies deps, UidFdTagger uidFdTagger) { - mContext = context; - mDeps = Objects.requireNonNull(deps, "Missing dependencies."); - mUidFdTagger = uidFdTagger; - try { - mNetd = mDeps.getNetdInstance(mContext); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be - * a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1. - */ - private static void checkInetAddress(String inetAddress) { - if (TextUtils.isEmpty(inetAddress)) { - throw new IllegalArgumentException("Unspecified address"); - } - - InetAddress checkAddr = InetAddresses.parseNumericAddress(inetAddress); - - if (checkAddr.isAnyLocalAddress()) { - throw new IllegalArgumentException("Inappropriate wildcard address: " + inetAddress); - } - } - - /** - * Checks the user-provided direction field and throws an IllegalArgumentException if it is not - * DIRECTION_IN or DIRECTION_OUT - */ - private void checkDirection(int direction) { - switch (direction) { - case IpSecManager.DIRECTION_OUT: - case IpSecManager.DIRECTION_IN: - return; - case IpSecManager.DIRECTION_FWD: - // Only NETWORK_STACK or MAINLINE_NETWORK_STACK allowed to use forward policies - PermissionUtils.enforceNetworkStackPermission(mContext); - return; - } - throw new IllegalArgumentException("Invalid Direction: " + direction); - } - - /** Get a new SPI and maintain the reservation in the system server */ - @Override - public synchronized IpSecSpiResponse allocateSecurityParameterIndex( - String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException { - checkInetAddress(destinationAddress); - // RFC 4303 Section 2.1 - 0=local, 1-255=reserved. - if (requestedSpi > 0 && requestedSpi < 256) { - throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255."); - } - Objects.requireNonNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); - - int callingUid = Binder.getCallingUid(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); - final int resourceId = mNextResourceId++; - - int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - try { - if (!userRecord.mSpiQuotaTracker.isAvailable()) { - return new IpSecSpiResponse( - IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi); - } - - spi = mNetd.ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi); - Log.d(TAG, "Allocated SPI " + spi); - userRecord.mSpiRecords.put( - resourceId, - new RefcountedResource( - new SpiRecord(resourceId, "", - destinationAddress, spi), binder)); - } catch (ServiceSpecificException e) { - if (e.errorCode == OsConstants.ENOENT) { - return new IpSecSpiResponse( - IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi); - } - throw e; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, spi); - } - - /* This method should only be called from Binder threads. Do not call this from - * within the system server as it will crash the system on failure. - */ - private void releaseResource(RefcountedResourceArray resArray, int resourceId) - throws RemoteException { - resArray.getRefcountedResourceOrThrow(resourceId).userRelease(); - } - - /** Release a previously allocated SPI that has been registered with the system server */ - @Override - public synchronized void releaseSecurityParameterIndex(int resourceId) throws RemoteException { - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - releaseResource(userRecord.mSpiRecords, resourceId); - } - - /** - * This function finds and forcibly binds to a random system port, ensuring that the port cannot - * be unbound. - * - *

A socket cannot be un-bound from a port if it was bound to that port by number. To select - * a random open port and then bind by number, this function creates a temp socket, binds to a - * random port (specifying 0), gets that port number, and then uses is to bind the user's UDP - * Encapsulation Socket forcibly, so that it cannot be un-bound by the user with the returned - * FileHandle. - * - *

The loop in this function handles the inherent race window between un-binding to a port - * and re-binding, during which the system could *technically* hand that port out to someone - * else. - */ - private int bindToRandomPort(FileDescriptor sockFd) throws IOException { - for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) { - try { - FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - Os.bind(probeSocket, INADDR_ANY, 0); - int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort(); - Os.close(probeSocket); - Log.v(TAG, "Binding to port " + port); - Os.bind(sockFd, INADDR_ANY, port); - return port; - } catch (ErrnoException e) { - // Someone miraculously claimed the port just after we closed probeSocket. - if (e.errno == OsConstants.EADDRINUSE) { - continue; - } - throw e.rethrowAsIOException(); - } - } - throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port"); - } - - /** - * Functional interface to do traffic tagging of given sockets to UIDs. - * - *

Specifically used by openUdpEncapsulationSocket to ensure data usage on the UDP encap - * sockets are billed to the UID that the UDP encap socket was created on behalf of. - * - *

Separate class so that the socket tagging logic can be mocked; TrafficStats uses static - * methods that cannot be easily mocked/tested. - */ - @VisibleForTesting - public interface UidFdTagger { - /** - * Sets socket tag to assign all traffic to the provided UID. - * - *

Since the socket is created on behalf of an unprivileged application, all traffic - * should be accounted to the UID of the unprivileged application. - */ - void tag(FileDescriptor fd, int uid) throws IOException; - } - - /** - * Open a socket via the system server and bind it to the specified port (random if port=0). - * This will return a PFD to the user that represent a bound UDP socket. The system server will - * cache the socket and a record of its owner so that it can and must be freed when no longer - * needed. - */ - @Override - public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder) - throws RemoteException { - if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) { - throw new IllegalArgumentException( - "Specified port number must be a valid non-reserved UDP port"); - } - Objects.requireNonNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); - - int callingUid = Binder.getCallingUid(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); - final int resourceId = mNextResourceId++; - - ParcelFileDescriptor pFd = null; - try { - if (!userRecord.mSocketQuotaTracker.isAvailable()) { - return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } - - FileDescriptor sockFd = null; - try { - sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - pFd = ParcelFileDescriptor.dup(sockFd); - } finally { - IoUtils.closeQuietly(sockFd); - } - - mUidFdTagger.tag(pFd.getFileDescriptor(), callingUid); - // This code is common to both the unspecified and specified port cases - Os.setsockoptInt( - pFd.getFileDescriptor(), - OsConstants.IPPROTO_UDP, - OsConstants.UDP_ENCAP, - OsConstants.UDP_ENCAP_ESPINUDP); - - mNetd.ipSecSetEncapSocketOwner(pFd, callingUid); - if (port != 0) { - Log.v(TAG, "Binding to port " + port); - Os.bind(pFd.getFileDescriptor(), INADDR_ANY, port); - } else { - port = bindToRandomPort(pFd.getFileDescriptor()); - } - - userRecord.mEncapSocketRecords.put( - resourceId, - new RefcountedResource( - new EncapSocketRecord(resourceId, pFd.getFileDescriptor(), port), - binder)); - return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, - pFd.getFileDescriptor()); - } catch (IOException | ErrnoException e) { - try { - if (pFd != null) { - pFd.close(); - } - } catch (IOException ex) { - // Nothing can be done at this point - Log.e(TAG, "Failed to close pFd."); - } - } - // If we make it to here, then something has gone wrong and we couldn't open a socket. - // The only reasonable condition that would cause that is resource unavailable. - return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } - - /** close a socket that has been been allocated by and registered with the system server */ - @Override - public synchronized void closeUdpEncapsulationSocket(int resourceId) throws RemoteException { - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - releaseResource(userRecord.mEncapSocketRecords, resourceId); - } - - /** - * Create a tunnel interface for use in IPSec tunnel mode. The system server will cache the - * tunnel interface and a record of its owner so that it can and must be freed when no longer - * needed. - */ - @Override - public synchronized IpSecTunnelInterfaceResponse createTunnelInterface( - String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder, - String callingPackage) { - enforceTunnelFeatureAndPermissions(callingPackage); - Objects.requireNonNull(binder, "Null Binder passed to createTunnelInterface"); - Objects.requireNonNull(underlyingNetwork, "No underlying network was specified"); - checkInetAddress(localAddr); - checkInetAddress(remoteAddr); - - // TODO: Check that underlying network exists, and IP addresses not assigned to a different - // network (b/72316676). - - int callerUid = Binder.getCallingUid(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(callerUid); - if (!userRecord.mTunnelQuotaTracker.isAvailable()) { - return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } - - final int resourceId = mNextResourceId++; - final int ikey = reserveNetId(); - final int okey = reserveNetId(); - String intfName = String.format("%s%d", INetd.IPSEC_INTERFACE_PREFIX, resourceId); - - try { - // Calls to netd: - // Create VTI - // Add inbound/outbound global policies - // (use reqid = 0) - mNetd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); - - BinderUtils.withCleanCallingIdentity(() -> { - NetdUtils.setInterfaceUp(mNetd, intfName); - }); - - for (int selAddrFamily : ADDRESS_FAMILIES) { - // Always send down correct local/remote addresses for template. - mNetd.ipSecAddSecurityPolicy( - callerUid, - selAddrFamily, - IpSecManager.DIRECTION_OUT, - localAddr, - remoteAddr, - 0, - okey, - 0xffffffff, - resourceId); - mNetd.ipSecAddSecurityPolicy( - callerUid, - selAddrFamily, - IpSecManager.DIRECTION_IN, - remoteAddr, - localAddr, - 0, - ikey, - 0xffffffff, - resourceId); - - // Add a forwarding policy on the tunnel interface. In order to support forwarding - // the IpSecTunnelInterface must have a forwarding policy matching the incoming SA. - // - // Unless a IpSecTransform is also applied against this interface in DIRECTION_FWD, - // forwarding will be blocked by default (as would be the case if this policy was - // absent). - // - // This is necessary only on the tunnel interface, and not any the interface to - // which traffic will be forwarded to. - mNetd.ipSecAddSecurityPolicy( - callerUid, - selAddrFamily, - IpSecManager.DIRECTION_FWD, - remoteAddr, - localAddr, - 0, - ikey, - 0xffffffff, - resourceId); - } - - userRecord.mTunnelInterfaceRecords.put( - resourceId, - new RefcountedResource( - new TunnelInterfaceRecord( - resourceId, - intfName, - underlyingNetwork, - localAddr, - remoteAddr, - ikey, - okey, - resourceId), - binder)); - return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName); - } catch (RemoteException e) { - // Release keys if we got an error. - releaseNetId(ikey); - releaseNetId(okey); - throw e.rethrowFromSystemServer(); - } catch (Throwable t) { - // Release keys if we got an error. - releaseNetId(ikey); - releaseNetId(okey); - throw t; - } - } - - /** - * Adds a new local address to the tunnel interface. This allows packets to be sent and received - * from multiple local IP addresses over the same tunnel. - */ - @Override - public synchronized void addAddressToTunnelInterface( - int tunnelResourceId, LinkAddress localAddr, String callingPackage) { - enforceTunnelFeatureAndPermissions(callingPackage); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - - // Get tunnelInterface record; if no such interface is found, will throw - // IllegalArgumentException - TunnelInterfaceRecord tunnelInterfaceInfo = - userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - - try { - // We can assume general validity of the IP address, since we get them as a - // LinkAddress, which does some validation. - mNetd.interfaceAddAddress( - tunnelInterfaceInfo.mInterfaceName, - localAddr.getAddress().getHostAddress(), - localAddr.getPrefixLength()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Remove a new local address from the tunnel interface. After removal, the address will no - * longer be available to send from, or receive on. - */ - @Override - public synchronized void removeAddressFromTunnelInterface( - int tunnelResourceId, LinkAddress localAddr, String callingPackage) { - enforceTunnelFeatureAndPermissions(callingPackage); - - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - // Get tunnelInterface record; if no such interface is found, will throw - // IllegalArgumentException - TunnelInterfaceRecord tunnelInterfaceInfo = - userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - - try { - // We can assume general validity of the IP address, since we get them as a - // LinkAddress, which does some validation. - mNetd.interfaceDelAddress( - tunnelInterfaceInfo.mInterfaceName, - localAddr.getAddress().getHostAddress(), - localAddr.getPrefixLength()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** Set TunnelInterface to use a specific underlying network. */ - @Override - public synchronized void setNetworkForTunnelInterface( - int tunnelResourceId, Network underlyingNetwork, String callingPackage) { - enforceTunnelFeatureAndPermissions(callingPackage); - Objects.requireNonNull(underlyingNetwork, "No underlying network was specified"); - - final UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - - // Get tunnelInterface record; if no such interface is found, will throw - // IllegalArgumentException. userRecord.mTunnelInterfaceRecords is never null - final TunnelInterfaceRecord tunnelInterfaceInfo = - userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - - final ConnectivityManager connectivityManager = - mContext.getSystemService(ConnectivityManager.class); - final LinkProperties lp = connectivityManager.getLinkProperties(underlyingNetwork); - if (tunnelInterfaceInfo.getInterfaceName().equals(lp.getInterfaceName())) { - throw new IllegalArgumentException( - "Underlying network cannot be the network being exposed by this tunnel"); - } - - // It is meaningless to check if the network exists or is valid because the network might - // disconnect at any time after it passes the check. - - tunnelInterfaceInfo.setUnderlyingNetwork(underlyingNetwork); - } - - /** - * Delete a TunnelInterface that has been been allocated by and registered with the system - * server - */ - @Override - public synchronized void deleteTunnelInterface( - int resourceId, String callingPackage) throws RemoteException { - enforceTunnelFeatureAndPermissions(callingPackage); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - releaseResource(userRecord.mTunnelInterfaceRecords, resourceId); - } - - @VisibleForTesting - void validateAlgorithms(IpSecConfig config) throws IllegalArgumentException { - IpSecAlgorithm auth = config.getAuthentication(); - IpSecAlgorithm crypt = config.getEncryption(); - IpSecAlgorithm aead = config.getAuthenticatedEncryption(); - - // Validate the algorithm set - Preconditions.checkArgument( - aead != null || crypt != null || auth != null, - "No Encryption or Authentication algorithms specified"); - Preconditions.checkArgument( - auth == null || auth.isAuthentication(), - "Unsupported algorithm for Authentication"); - Preconditions.checkArgument( - crypt == null || crypt.isEncryption(), "Unsupported algorithm for Encryption"); - Preconditions.checkArgument( - aead == null || aead.isAead(), - "Unsupported algorithm for Authenticated Encryption"); - Preconditions.checkArgument( - aead == null || (auth == null && crypt == null), - "Authenticated Encryption is mutually exclusive with other Authentication " - + "or Encryption algorithms"); - } - - private int getFamily(String inetAddress) { - int family = AF_UNSPEC; - InetAddress checkAddress = InetAddresses.parseNumericAddress(inetAddress); - if (checkAddress instanceof Inet4Address) { - family = AF_INET; - } else if (checkAddress instanceof Inet6Address) { - family = AF_INET6; - } - return family; - } - - /** - * Checks an IpSecConfig parcel to ensure that the contents are valid and throws an - * IllegalArgumentException if they are not. - */ - private void checkIpSecConfig(IpSecConfig config) { - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - - switch (config.getEncapType()) { - case IpSecTransform.ENCAP_NONE: - break; - case IpSecTransform.ENCAP_ESPINUDP: - case IpSecTransform.ENCAP_ESPINUDP_NON_IKE: - // Retrieve encap socket record; will throw IllegalArgumentException if not found - userRecord.mEncapSocketRecords.getResourceOrThrow( - config.getEncapSocketResourceId()); - - int port = config.getEncapRemotePort(); - if (port <= 0 || port > 0xFFFF) { - throw new IllegalArgumentException("Invalid remote UDP port: " + port); - } - break; - default: - throw new IllegalArgumentException("Invalid Encap Type: " + config.getEncapType()); - } - - validateAlgorithms(config); - - // Retrieve SPI record; will throw IllegalArgumentException if not found - SpiRecord s = userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId()); - - // Check to ensure that SPI has not already been used. - if (s.getOwnedByTransform()) { - throw new IllegalStateException("SPI already in use; cannot be used in new Transforms"); - } - - // If no remote address is supplied, then use one from the SPI. - if (TextUtils.isEmpty(config.getDestinationAddress())) { - config.setDestinationAddress(s.getDestinationAddress()); - } - - // All remote addresses must match - if (!config.getDestinationAddress().equals(s.getDestinationAddress())) { - throw new IllegalArgumentException("Mismatched remote addresseses."); - } - - // This check is technically redundant due to the chain of custody between the SPI and - // the IpSecConfig, but in the future if the dest is allowed to be set explicitly in - // the transform, this will prevent us from messing up. - checkInetAddress(config.getDestinationAddress()); - - // Require a valid source address for all transforms. - checkInetAddress(config.getSourceAddress()); - - // Check to ensure source and destination have the same address family. - String sourceAddress = config.getSourceAddress(); - String destinationAddress = config.getDestinationAddress(); - int sourceFamily = getFamily(sourceAddress); - int destinationFamily = getFamily(destinationAddress); - if (sourceFamily != destinationFamily) { - throw new IllegalArgumentException( - "Source address (" - + sourceAddress - + ") and destination address (" - + destinationAddress - + ") have different address families."); - } - - // Throw an error if UDP Encapsulation is not used in IPv4. - if (config.getEncapType() != IpSecTransform.ENCAP_NONE && sourceFamily != AF_INET) { - throw new IllegalArgumentException( - "UDP Encapsulation is not supported for this address family"); - } - - switch (config.getMode()) { - case IpSecTransform.MODE_TRANSPORT: - break; - case IpSecTransform.MODE_TUNNEL: - break; - default: - throw new IllegalArgumentException( - "Invalid IpSecTransform.mode: " + config.getMode()); - } - - config.setMarkValue(0); - config.setMarkMask(0); - } - - private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS; - - private void enforceTunnelFeatureAndPermissions(String callingPackage) { - if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)) { - throw new UnsupportedOperationException( - "IPsec Tunnel Mode requires PackageManager.FEATURE_IPSEC_TUNNELS"); - } - - Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels"); - - // OP_MANAGE_IPSEC_TUNNELS will return MODE_ERRORED by default, including for the system - // server. If the appop is not granted, require that the caller has the MANAGE_IPSEC_TUNNELS - // permission or is the System Server. - if (AppOpsManager.MODE_ALLOWED == getAppOpsManager().noteOpNoThrow( - TUNNEL_OP, Binder.getCallingUid(), callingPackage)) { - return; - } - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); - } - - private void createOrUpdateTransform( - IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord) - throws RemoteException { - - int encapType = c.getEncapType(), encapLocalPort = 0, encapRemotePort = 0; - if (encapType != IpSecTransform.ENCAP_NONE) { - encapLocalPort = socketRecord.getPort(); - encapRemotePort = c.getEncapRemotePort(); - } - - IpSecAlgorithm auth = c.getAuthentication(); - IpSecAlgorithm crypt = c.getEncryption(); - IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(); - - String cryptName; - if (crypt == null) { - cryptName = (authCrypt == null) ? IpSecAlgorithm.CRYPT_NULL : ""; - } else { - cryptName = crypt.getName(); - } - - mNetd.ipSecAddSecurityAssociation( - Binder.getCallingUid(), - c.getMode(), - c.getSourceAddress(), - c.getDestinationAddress(), - (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0, - spiRecord.getSpi(), - c.getMarkValue(), - c.getMarkMask(), - (auth != null) ? auth.getName() : "", - (auth != null) ? auth.getKey() : new byte[] {}, - (auth != null) ? auth.getTruncationLengthBits() : 0, - cryptName, - (crypt != null) ? crypt.getKey() : new byte[] {}, - (crypt != null) ? crypt.getTruncationLengthBits() : 0, - (authCrypt != null) ? authCrypt.getName() : "", - (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, - (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, - encapType, - encapLocalPort, - encapRemotePort, - c.getXfrmInterfaceId()); - } - - /** - * Create a IPsec transform, which represents a single security association in the kernel. The - * transform will be cached by the system server and must be freed when no longer needed. It is - * possible to free one, deleting the SA from underneath sockets that are using it, which will - * result in all of those sockets becoming unable to send or receive data. - */ - @Override - public synchronized IpSecTransformResponse createTransform( - IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException { - Objects.requireNonNull(c); - if (c.getMode() == IpSecTransform.MODE_TUNNEL) { - enforceTunnelFeatureAndPermissions(callingPackage); - } - checkIpSecConfig(c); - Objects.requireNonNull(binder, "Null Binder passed to createTransform"); - final int resourceId = mNextResourceId++; - - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - List dependencies = new ArrayList<>(); - - if (!userRecord.mTransformQuotaTracker.isAvailable()) { - return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } - - EncapSocketRecord socketRecord = null; - if (c.getEncapType() != IpSecTransform.ENCAP_NONE) { - RefcountedResource refcountedSocketRecord = - userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow( - c.getEncapSocketResourceId()); - dependencies.add(refcountedSocketRecord); - socketRecord = refcountedSocketRecord.getResource(); - } - - RefcountedResource refcountedSpiRecord = - userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId()); - dependencies.add(refcountedSpiRecord); - SpiRecord spiRecord = refcountedSpiRecord.getResource(); - - createOrUpdateTransform(c, resourceId, spiRecord, socketRecord); - - // SA was created successfully, time to construct a record and lock it away - userRecord.mTransformRecords.put( - resourceId, - new RefcountedResource( - new TransformRecord(resourceId, c, spiRecord, socketRecord), - binder, - dependencies.toArray(new RefcountedResource[dependencies.size()]))); - return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId); - } - - /** - * Delete a transport mode transform that was previously allocated by + registered with the - * system server. If this is called on an inactive (or non-existent) transform, it will not - * return an error. It's safe to de-allocate transforms that may have already been deleted for - * other reasons. - */ - @Override - public synchronized void deleteTransform(int resourceId) throws RemoteException { - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - releaseResource(userRecord.mTransformRecords, resourceId); - } - - /** - * Apply an active transport mode transform to a socket, which will apply the IPsec security - * association as a correspondent policy to the provided socket - */ - @Override - public synchronized void applyTransportModeTransform( - ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException { - int callingUid = Binder.getCallingUid(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); - checkDirection(direction); - // Get transform record; if no transform is found, will throw IllegalArgumentException - TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId); - - // TODO: make this a function. - if (info.mPid != getCallingPid() || info.mUid != callingUid) { - throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); - } - - // Get config and check that to-be-applied transform has the correct mode - IpSecConfig c = info.getConfig(); - Preconditions.checkArgument( - c.getMode() == IpSecTransform.MODE_TRANSPORT, - "Transform mode was not Transport mode; cannot be applied to a socket"); - - mNetd.ipSecApplyTransportModeTransform( - socket, - callingUid, - direction, - c.getSourceAddress(), - c.getDestinationAddress(), - info.getSpiRecord().getSpi()); - } - - /** - * Remove transport mode transforms from a socket, applying the default (empty) policy. This - * ensures that NO IPsec policy is applied to the socket (would be the equivalent of applying a - * policy that performs no IPsec). Today the resourceId parameter is passed but not used: - * reserved for future improved input validation. - */ - @Override - public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket) - throws RemoteException { - mNetd.ipSecRemoveTransportModeTransform(socket); - } - - /** - * Apply an active tunnel mode transform to a TunnelInterface, which will apply the IPsec - * security association as a correspondent policy to the provided interface - */ - @Override - public synchronized void applyTunnelModeTransform( - int tunnelResourceId, int direction, - int transformResourceId, String callingPackage) throws RemoteException { - enforceTunnelFeatureAndPermissions(callingPackage); - checkDirection(direction); - - int callingUid = Binder.getCallingUid(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); - - // Get transform record; if no transform is found, will throw IllegalArgumentException - TransformRecord transformInfo = - userRecord.mTransformRecords.getResourceOrThrow(transformResourceId); - - // Get tunnelInterface record; if no such interface is found, will throw - // IllegalArgumentException - TunnelInterfaceRecord tunnelInterfaceInfo = - userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - - // Get config and check that to-be-applied transform has the correct mode - IpSecConfig c = transformInfo.getConfig(); - Preconditions.checkArgument( - c.getMode() == IpSecTransform.MODE_TUNNEL, - "Transform mode was not Tunnel mode; cannot be applied to a tunnel interface"); - - EncapSocketRecord socketRecord = null; - if (c.getEncapType() != IpSecTransform.ENCAP_NONE) { - socketRecord = - userRecord.mEncapSocketRecords.getResourceOrThrow(c.getEncapSocketResourceId()); - } - SpiRecord spiRecord = transformInfo.getSpiRecord(); - - int mark = - (direction == IpSecManager.DIRECTION_OUT) - ? tunnelInterfaceInfo.getOkey() - : tunnelInterfaceInfo.getIkey(); // Ikey also used for FWD policies - - try { - // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip - // SPI matching as part of the template resolution. - int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - c.setXfrmInterfaceId(tunnelInterfaceInfo.getIfId()); - - // TODO: enable this when UPDSA supports updating marks. Adding kernel support upstream - // (and backporting) would allow us to narrow the mark space, and ensure that the SA - // and SPs have matching marks (as VTI are meant to be built). - // Currently update does nothing with marks. Leave empty (defaulting to 0) to ensure the - // config matches the actual allocated resources in the kernel. - // All SAs will have zero marks (from creation time), and any policy that matches the - // same src/dst could match these SAs. Non-IpSecService governed processes that - // establish floating policies with the same src/dst may result in undefined - // behavior. This is generally limited to vendor code due to the permissions - // (CAP_NET_ADMIN) required. - // - // c.setMarkValue(mark); - // c.setMarkMask(0xffffffff); - - if (direction == IpSecManager.DIRECTION_OUT) { - // Set output mark via underlying network (output only) - c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork()); - - // Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys, - // but want to guarantee outbound packets are sent over the new SA. - spi = spiRecord.getSpi(); - } - - // Always update the policy with the relevant XFRM_IF_ID - for (int selAddrFamily : ADDRESS_FAMILIES) { - mNetd.ipSecUpdateSecurityPolicy( - callingUid, - selAddrFamily, - direction, - transformInfo.getConfig().getSourceAddress(), - transformInfo.getConfig().getDestinationAddress(), - spi, // If outbound, also add SPI to the policy. - mark, // Must always set policy mark; ikey/okey for VTIs - 0xffffffff, - c.getXfrmInterfaceId()); - } - - // Update SA with tunnel mark (ikey or okey based on direction) - createOrUpdateTransform(c, transformResourceId, spiRecord, socketRecord); - } catch (ServiceSpecificException e) { - if (e.errorCode == EINVAL) { - throw new IllegalArgumentException(e.toString()); - } else { - throw e; - } - } - } - - @Override - protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mContext.enforceCallingOrSelfPermission(DUMP, TAG); - - pw.println("IpSecService dump:"); - pw.println(); - - pw.println("mUserResourceTracker:"); - pw.println(mUserResourceTracker); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnector.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnector.java deleted file mode 100644 index ec8d7798e17e5..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnector.java +++ /dev/null @@ -1,704 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import android.net.LocalSocket; -import android.net.LocalSocketAddress; -import android.os.Build; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.SystemClock; -import android.util.LocalLog; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.Objects; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Generic connector class for interfacing with a native daemon which uses the - * {@code libsysutils} FrameworkListener protocol. - */ -final class NativeDaemonConnector implements Runnable, Handler.Callback { - private final static boolean VDBG = false; - - private final String TAG; - - private String mSocket; - private OutputStream mOutputStream; - private LocalLog mLocalLog; - - private volatile boolean mDebug = false; - private volatile Object mWarnIfHeld; - - private final ResponseQueue mResponseQueue; - - private final PowerManager.WakeLock mWakeLock; - - private final Looper mLooper; - - private INativeDaemonConnectorCallbacks mCallbacks; - private Handler mCallbackHandler; - - private AtomicInteger mSequenceNumber; - - private static final long DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */ - private static final long WARN_EXECUTE_DELAY_MS = 500; /* .5 sec */ - - /** Lock held whenever communicating with native daemon. */ - private final Object mDaemonLock = new Object(); - - private final int BUFFER_SIZE = 4096; - - NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, - int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) { - mCallbacks = callbacks; - mSocket = socket; - mResponseQueue = new ResponseQueue(responseQueueSize); - mWakeLock = wl; - if (mWakeLock != null) { - mWakeLock.setReferenceCounted(true); - } - mSequenceNumber = new AtomicInteger(0); - TAG = logTag != null ? logTag : "NativeDaemonConnector"; - mLocalLog = new LocalLog(maxLogSize); - final HandlerThread thread = new HandlerThread(TAG); - thread.start(); - mLooper = thread.getLooper(); - } - - /** - * Enable Set debugging mode, which causes messages to also be written to both - * {@link Log} in addition to internal log. - */ - public void setDebug(boolean debug) { - mDebug = debug; - } - - /** - * Like SystemClock.uptimeMillis, except truncated to an int so it will fit in a message arg. - * Inaccurate across 49.7 days of uptime, but only used for debugging. - */ - private int uptimeMillisInt() { - return (int) SystemClock.uptimeMillis() & Integer.MAX_VALUE; - } - - /** - * Yell loudly if someone tries making future {@link #execute(Command)} - * calls while holding a lock on the given object. - */ - public void setWarnIfHeld(Object warnIfHeld) { - if (mWarnIfHeld != null) { - throw new IllegalStateException("warnIfHeld is already set."); - } - mWarnIfHeld = Objects.requireNonNull(warnIfHeld); - } - - @Override - public void run() { - mCallbackHandler = new Handler(mLooper, this); - - while (true) { - try { - listenToSocket(); - } catch (Exception e) { - loge("Error in NativeDaemonConnector: " + e); - SystemClock.sleep(5000); - } - } - } - - @Override - public boolean handleMessage(Message msg) { - final String event = (String) msg.obj; - final int start = uptimeMillisInt(); - final int sent = msg.arg1; - try { - if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { - log(String.format("Unhandled event '%s'", event)); - } - } catch (Exception e) { - loge("Error handling '" + event + "': " + e); - } finally { - if (mCallbacks.onCheckHoldWakeLock(msg.what) && mWakeLock != null) { - mWakeLock.release(); - } - final int end = uptimeMillisInt(); - if (start > sent && start - sent > WARN_EXECUTE_DELAY_MS) { - loge(String.format("NDC event {%s} processed too late: %dms", event, start - sent)); - } - if (end > start && end - start > WARN_EXECUTE_DELAY_MS) { - loge(String.format("NDC event {%s} took too long: %dms", event, end - start)); - } - } - return true; - } - - private LocalSocketAddress determineSocketAddress() { - // If we're testing, set up a socket in a namespace that's accessible to test code. - // In order to ensure that unprivileged apps aren't able to impersonate native daemons on - // production devices, even if said native daemons ill-advisedly pick a socket name that - // starts with __test__, only allow this on debug builds. - if (mSocket.startsWith("__test__") && Build.isDebuggable()) { - return new LocalSocketAddress(mSocket); - } else { - return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED); - } - } - - private void listenToSocket() throws IOException { - LocalSocket socket = null; - - try { - socket = new LocalSocket(); - LocalSocketAddress address = determineSocketAddress(); - - socket.connect(address); - - InputStream inputStream = socket.getInputStream(); - synchronized (mDaemonLock) { - mOutputStream = socket.getOutputStream(); - } - - mCallbacks.onDaemonConnected(); - - FileDescriptor[] fdList = null; - byte[] buffer = new byte[BUFFER_SIZE]; - int start = 0; - - while (true) { - int count = inputStream.read(buffer, start, BUFFER_SIZE - start); - if (count < 0) { - loge("got " + count + " reading with start = " + start); - break; - } - fdList = socket.getAncillaryFileDescriptors(); - - // Add our starting point to the count and reset the start. - count += start; - start = 0; - - for (int i = 0; i < count; i++) { - if (buffer[i] == 0) { - // Note - do not log this raw message since it may contain - // sensitive data - final String rawEvent = new String( - buffer, start, i - start, StandardCharsets.UTF_8); - - boolean releaseWl = false; - try { - final NativeDaemonEvent event = - NativeDaemonEvent.parseRawEvent(rawEvent, fdList); - - log("RCV <- {" + event + "}"); - - if (event.isClassUnsolicited()) { - // TODO: migrate to sending NativeDaemonEvent instances - if (mCallbacks.onCheckHoldWakeLock(event.getCode()) - && mWakeLock != null) { - mWakeLock.acquire(); - releaseWl = true; - } - Message msg = mCallbackHandler.obtainMessage( - event.getCode(), uptimeMillisInt(), 0, event.getRawEvent()); - if (mCallbackHandler.sendMessage(msg)) { - releaseWl = false; - } - } else { - mResponseQueue.add(event.getCmdNumber(), event); - } - } catch (IllegalArgumentException e) { - log("Problem parsing message " + e); - } finally { - if (releaseWl) { - mWakeLock.release(); - } - } - - start = i + 1; - } - } - - if (start == 0) { - log("RCV incomplete"); - } - - // We should end at the amount we read. If not, compact then - // buffer and read again. - if (start != count) { - final int remaining = BUFFER_SIZE - start; - System.arraycopy(buffer, start, buffer, 0, remaining); - start = remaining; - } else { - start = 0; - } - } - } catch (IOException ex) { - loge("Communications error: " + ex); - throw ex; - } finally { - synchronized (mDaemonLock) { - if (mOutputStream != null) { - try { - loge("closing stream for " + mSocket); - mOutputStream.close(); - } catch (IOException e) { - loge("Failed closing output stream: " + e); - } - mOutputStream = null; - } - } - - try { - if (socket != null) { - socket.close(); - } - } catch (IOException ex) { - loge("Failed closing socket: " + ex); - } - } - } - - /** - * Wrapper around argument that indicates it's sensitive and shouldn't be - * logged. - */ - public static class SensitiveArg { - private final Object mArg; - - public SensitiveArg(Object arg) { - mArg = arg; - } - - @Override - public String toString() { - return String.valueOf(mArg); - } - } - - /** - * Make command for daemon, escaping arguments as needed. - */ - @VisibleForTesting - static void makeCommand(StringBuilder rawBuilder, StringBuilder logBuilder, int sequenceNumber, - String cmd, Object... args) { - if (cmd.indexOf('\0') >= 0) { - throw new IllegalArgumentException("Unexpected command: " + cmd); - } - if (cmd.indexOf(' ') >= 0) { - throw new IllegalArgumentException("Arguments must be separate from command"); - } - - rawBuilder.append(sequenceNumber).append(' ').append(cmd); - logBuilder.append(sequenceNumber).append(' ').append(cmd); - for (Object arg : args) { - final String argString = String.valueOf(arg); - if (argString.indexOf('\0') >= 0) { - throw new IllegalArgumentException("Unexpected argument: " + arg); - } - - rawBuilder.append(' '); - logBuilder.append(' '); - - appendEscaped(rawBuilder, argString); - if (arg instanceof SensitiveArg) { - logBuilder.append("[scrubbed]"); - } else { - appendEscaped(logBuilder, argString); - } - } - - rawBuilder.append('\0'); - } - - /** - * Method that waits until all asychronous notifications sent by the native daemon have - * been processed. This method must not be called on the notification thread or an - * exception will be thrown. - */ - public void waitForCallbacks() { - if (Thread.currentThread() == mLooper.getThread()) { - throw new IllegalStateException("Must not call this method on callback thread"); - } - - final CountDownLatch latch = new CountDownLatch(1); - mCallbackHandler.post(new Runnable() { - @Override - public void run() { - latch.countDown(); - } - }); - try { - latch.await(); - } catch (InterruptedException e) { - Log.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e); - } - } - - /** - * Issue the given command to the native daemon and return a single expected - * response. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent execute(Command cmd) throws NativeDaemonConnectorException { - return execute(cmd.mCmd, cmd.mArguments.toArray()); - } - - /** - * Issue the given command to the native daemon and return a single expected - * response. Any arguments must be separated from base command so they can - * be properly escaped. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent execute(String cmd, Object... args) - throws NativeDaemonConnectorException { - return execute(DEFAULT_TIMEOUT, cmd, args); - } - - public NativeDaemonEvent execute(long timeoutMs, String cmd, Object... args) - throws NativeDaemonConnectorException { - final NativeDaemonEvent[] events = executeForList(timeoutMs, cmd, args); - if (events.length != 1) { - throw new NativeDaemonConnectorException( - "Expected exactly one response, but received " + events.length); - } - return events[0]; - } - - /** - * Issue the given command to the native daemon and return any - * {@link NativeDaemonEvent#isClassContinue()} responses, including the - * final terminal response. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent[] executeForList(Command cmd) throws NativeDaemonConnectorException { - return executeForList(cmd.mCmd, cmd.mArguments.toArray()); - } - - /** - * Issue the given command to the native daemon and return any - * {@link NativeDaemonEvent#isClassContinue()} responses, including the - * final terminal response. Any arguments must be separated from base - * command so they can be properly escaped. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent[] executeForList(String cmd, Object... args) - throws NativeDaemonConnectorException { - return executeForList(DEFAULT_TIMEOUT, cmd, args); - } - - /** - * Issue the given command to the native daemon and return any {@linke - * NativeDaemonEvent@isClassContinue()} responses, including the final - * terminal response. Note that the timeout does not count time in deep - * sleep. Any arguments must be separated from base command so they can be - * properly escaped. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args) - throws NativeDaemonConnectorException { - if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) { - Log.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" - + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable()); - } - - final long startTime = SystemClock.elapsedRealtime(); - - final ArrayList events = new ArrayList<>(); - - final StringBuilder rawBuilder = new StringBuilder(); - final StringBuilder logBuilder = new StringBuilder(); - final int sequenceNumber = mSequenceNumber.incrementAndGet(); - - makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args); - - final String rawCmd = rawBuilder.toString(); - final String logCmd = logBuilder.toString(); - - log("SND -> {" + logCmd + "}"); - - synchronized (mDaemonLock) { - if (mOutputStream == null) { - throw new NativeDaemonConnectorException("missing output stream"); - } else { - try { - mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new NativeDaemonConnectorException("problem sending command", e); - } - } - } - - NativeDaemonEvent event = null; - do { - event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd); - if (event == null) { - loge("timed-out waiting for response to " + logCmd); - throw new NativeDaemonTimeoutException(logCmd, event); - } - if (VDBG) log("RMV <- {" + event + "}"); - events.add(event); - } while (event.isClassContinue()); - - final long endTime = SystemClock.elapsedRealtime(); - if (endTime - startTime > WARN_EXECUTE_DELAY_MS) { - loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)"); - } - - if (event.isClassClientError()) { - throw new NativeDaemonArgumentException(logCmd, event); - } - if (event.isClassServerError()) { - throw new NativeDaemonFailureException(logCmd, event); - } - - return events.toArray(new NativeDaemonEvent[events.size()]); - } - - /** - * Append the given argument to {@link StringBuilder}, escaping as needed, - * and surrounding with quotes when it contains spaces. - */ - @VisibleForTesting - static void appendEscaped(StringBuilder builder, String arg) { - final boolean hasSpaces = arg.indexOf(' ') >= 0; - if (hasSpaces) { - builder.append('"'); - } - - final int length = arg.length(); - for (int i = 0; i < length; i++) { - final char c = arg.charAt(i); - - if (c == '"') { - builder.append("\\\""); - } else if (c == '\\') { - builder.append("\\\\"); - } else { - builder.append(c); - } - } - - if (hasSpaces) { - builder.append('"'); - } - } - - private static class NativeDaemonArgumentException extends NativeDaemonConnectorException { - public NativeDaemonArgumentException(String command, NativeDaemonEvent event) { - super(command, event); - } - - @Override - public IllegalArgumentException rethrowAsParcelableException() { - throw new IllegalArgumentException(getMessage(), this); - } - } - - private static class NativeDaemonFailureException extends NativeDaemonConnectorException { - public NativeDaemonFailureException(String command, NativeDaemonEvent event) { - super(command, event); - } - } - - /** - * Command builder that handles argument list building. Any arguments must - * be separated from base command so they can be properly escaped. - */ - public static class Command { - private String mCmd; - private ArrayList mArguments = new ArrayList<>(); - - public Command(String cmd, Object... args) { - mCmd = cmd; - for (Object arg : args) { - appendArg(arg); - } - } - - public Command appendArg(Object arg) { - mArguments.add(arg); - return this; - } - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mLocalLog.dump(fd, pw, args); - pw.println(); - mResponseQueue.dump(fd, pw, args); - } - - private void log(String logstring) { - if (mDebug) Log.d(TAG, logstring); - mLocalLog.log(logstring); - } - - private void loge(String logstring) { - Log.e(TAG, logstring); - mLocalLog.log(logstring); - } - - private static class ResponseQueue { - - private static class PendingCmd { - public final int cmdNum; - public final String logCmd; - - public BlockingQueue responses = - new ArrayBlockingQueue(10); - - // The availableResponseCount member is used to track when we can remove this - // instance from the ResponseQueue. - // This is used under the protection of a sync of the mPendingCmds object. - // A positive value means we've had more writers retreive this object while - // a negative value means we've had more readers. When we've had an equal number - // (it goes to zero) we can remove this object from the mPendingCmds list. - // Note that we may have more responses for this command (and more readers - // coming), but that would result in a new PendingCmd instance being created - // and added with the same cmdNum. - // Also note that when this goes to zero it just means a parity of readers and - // writers have retrieved this object - not that they are done using it. The - // responses queue may well have more responses yet to be read or may get more - // responses added to it. But all those readers/writers have retreived and - // hold references to this instance already so it can be removed from - // mPendingCmds queue. - public int availableResponseCount; - - public PendingCmd(int cmdNum, String logCmd) { - this.cmdNum = cmdNum; - this.logCmd = logCmd; - } - } - - private final LinkedList mPendingCmds; - private int mMaxCount; - - ResponseQueue(int maxCount) { - mPendingCmds = new LinkedList(); - mMaxCount = maxCount; - } - - public void add(int cmdNum, NativeDaemonEvent response) { - PendingCmd found = null; - synchronized (mPendingCmds) { - for (PendingCmd pendingCmd : mPendingCmds) { - if (pendingCmd.cmdNum == cmdNum) { - found = pendingCmd; - break; - } - } - if (found == null) { - // didn't find it - make sure our queue isn't too big before adding - while (mPendingCmds.size() >= mMaxCount) { - Log.e("NativeDaemonConnector.ResponseQueue", - "more buffered than allowed: " + mPendingCmds.size() + - " >= " + mMaxCount); - // let any waiter timeout waiting for this - PendingCmd pendingCmd = mPendingCmds.remove(); - Log.e("NativeDaemonConnector.ResponseQueue", - "Removing request: " + pendingCmd.logCmd + " (" + - pendingCmd.cmdNum + ")"); - } - found = new PendingCmd(cmdNum, null); - mPendingCmds.add(found); - } - found.availableResponseCount++; - // if a matching remove call has already retrieved this we can remove this - // instance from our list - if (found.availableResponseCount == 0) mPendingCmds.remove(found); - } - try { - found.responses.put(response); - } catch (InterruptedException e) { } - } - - // note that the timeout does not count time in deep sleep. If you don't want - // the device to sleep, hold a wakelock - public NativeDaemonEvent remove(int cmdNum, long timeoutMs, String logCmd) { - PendingCmd found = null; - synchronized (mPendingCmds) { - for (PendingCmd pendingCmd : mPendingCmds) { - if (pendingCmd.cmdNum == cmdNum) { - found = pendingCmd; - break; - } - } - if (found == null) { - found = new PendingCmd(cmdNum, logCmd); - mPendingCmds.add(found); - } - found.availableResponseCount--; - // if a matching add call has already retrieved this we can remove this - // instance from our list - if (found.availableResponseCount == 0) mPendingCmds.remove(found); - } - NativeDaemonEvent result = null; - try { - result = found.responses.poll(timeoutMs, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) {} - if (result == null) { - Log.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response"); - } - return result; - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("Pending requests:"); - synchronized (mPendingCmds) { - for (PendingCmd pendingCmd : mPendingCmds) { - pw.println(" Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.logCmd); - } - } - } - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnectorException.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnectorException.java deleted file mode 100644 index 4d8881c68324e..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonConnectorException.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2006 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; - -import android.os.Parcel; - -/** - * An exception that indicates there was an error with a - * {@link NativeDaemonConnector} operation. - */ -public class NativeDaemonConnectorException extends Exception { - private String mCmd; - private NativeDaemonEvent mEvent; - - public NativeDaemonConnectorException(String detailMessage) { - super(detailMessage); - } - - public NativeDaemonConnectorException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - } - - public NativeDaemonConnectorException(String cmd, NativeDaemonEvent event) { - super("command '" + cmd + "' failed with '" + event + "'"); - mCmd = cmd; - mEvent = event; - } - - public int getCode() { - return mEvent != null ? mEvent.getCode() : -1; - } - - public String getCmd() { - return mCmd; - } - - /** - * Rethrow as a {@link RuntimeException} subclass that is handled by - * {@link Parcel#writeException(Exception)}. - */ - public IllegalArgumentException rethrowAsParcelableException() { - throw new IllegalStateException(getMessage(), this); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonEvent.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonEvent.java deleted file mode 100644 index 568369434629b..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonEvent.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import android.util.Log; - -import java.io.FileDescriptor; -import java.util.ArrayList; - -/** - * Parsed event from native side of {@link NativeDaemonConnector}. - */ -public class NativeDaemonEvent { - - // TODO: keep class ranges in sync with ResponseCode.h - // TODO: swap client and server error ranges to roughly mirror HTTP spec - - private final int mCmdNumber; - private final int mCode; - private final String mMessage; - private final String mRawEvent; - private final String mLogMessage; - private String[] mParsed; - private FileDescriptor[] mFdList; - - private NativeDaemonEvent(int cmdNumber, int code, String message, - String rawEvent, String logMessage, FileDescriptor[] fdList) { - mCmdNumber = cmdNumber; - mCode = code; - mMessage = message; - mRawEvent = rawEvent; - mLogMessage = logMessage; - mParsed = null; - mFdList = fdList; - } - - static public final String SENSITIVE_MARKER = "{{sensitive}}"; - - public int getCmdNumber() { - return mCmdNumber; - } - - public int getCode() { - return mCode; - } - - public String getMessage() { - return mMessage; - } - - public FileDescriptor[] getFileDescriptors() { - return mFdList; - } - - @Deprecated - public String getRawEvent() { - return mRawEvent; - } - - @Override - public String toString() { - return mLogMessage; - } - - /** - * Test if event represents a partial response which is continued in - * additional subsequent events. - */ - public boolean isClassContinue() { - return mCode >= 100 && mCode < 200; - } - - /** - * Test if event represents a command success. - */ - public boolean isClassOk() { - return mCode >= 200 && mCode < 300; - } - - /** - * Test if event represents a remote native daemon error. - */ - public boolean isClassServerError() { - return mCode >= 400 && mCode < 500; - } - - /** - * Test if event represents a command syntax or argument error. - */ - public boolean isClassClientError() { - return mCode >= 500 && mCode < 600; - } - - /** - * Test if event represents an unsolicited event from native daemon. - */ - public boolean isClassUnsolicited() { - return isClassUnsolicited(mCode); - } - - private static boolean isClassUnsolicited(int code) { - return code >= 600 && code < 700; - } - - /** - * Verify this event matches the given code. - * - * @throws IllegalStateException if {@link #getCode()} doesn't match. - */ - public void checkCode(int code) { - if (mCode != code) { - throw new IllegalStateException("Expected " + code + " but was: " + this); - } - } - - /** - * Parse the given raw event into {@link NativeDaemonEvent} instance. - * - * @throws IllegalArgumentException when line doesn't match format expected - * from native side. - */ - public static NativeDaemonEvent parseRawEvent(String rawEvent, FileDescriptor[] fdList) { - final String[] parsed = rawEvent.split(" "); - if (parsed.length < 2) { - throw new IllegalArgumentException("Insufficient arguments"); - } - - int skiplength = 0; - - final int code; - try { - code = Integer.parseInt(parsed[0]); - skiplength = parsed[0].length() + 1; - } catch (NumberFormatException e) { - throw new IllegalArgumentException("problem parsing code", e); - } - - int cmdNumber = -1; - if (isClassUnsolicited(code) == false) { - if (parsed.length < 3) { - throw new IllegalArgumentException("Insufficient arguemnts"); - } - try { - cmdNumber = Integer.parseInt(parsed[1]); - skiplength += parsed[1].length() + 1; - } catch (NumberFormatException e) { - throw new IllegalArgumentException("problem parsing cmdNumber", e); - } - } - - String logMessage = rawEvent; - if (parsed.length > 2 && parsed[2].equals(SENSITIVE_MARKER)) { - skiplength += parsed[2].length() + 1; - logMessage = parsed[0] + " " + parsed[1] + " {}"; - } - - final String message = rawEvent.substring(skiplength); - - return new NativeDaemonEvent(cmdNumber, code, message, rawEvent, logMessage, fdList); - } - - /** - * Filter the given {@link NativeDaemonEvent} list, returning - * {@link #getMessage()} for any events matching the requested code. - */ - public static String[] filterMessageList(NativeDaemonEvent[] events, int matchCode) { - final ArrayList result = new ArrayList<>(); - for (NativeDaemonEvent event : events) { - if (event.getCode() == matchCode) { - result.add(event.getMessage()); - } - } - return result.toArray(new String[result.size()]); - } - - /** - * Find the Nth field of the event. - * - * This ignores and code or cmdNum, the first return value is given for N=0. - * Also understands "\"quoted\" multiword responses" and tries them as a single field - */ - public String getField(int n) { - if (mParsed == null) { - mParsed = unescapeArgs(mRawEvent); - } - n += 2; // skip code and command# - if (n > mParsed.length) return null; - return mParsed[n]; - } - - public static String[] unescapeArgs(String rawEvent) { - final boolean DEBUG_ROUTINE = false; - final String LOGTAG = "unescapeArgs"; - final ArrayList parsed = new ArrayList(); - final int length = rawEvent.length(); - int current = 0; - int wordEnd = -1; - boolean quoted = false; - - if (DEBUG_ROUTINE) Log.e(LOGTAG, "parsing '" + rawEvent + "'"); - if (rawEvent.charAt(current) == '\"') { - quoted = true; - current++; - } - while (current < length) { - // find the end of the word - char terminator = quoted ? '\"' : ' '; - wordEnd = current; - while (wordEnd < length && rawEvent.charAt(wordEnd) != terminator) { - if (rawEvent.charAt(wordEnd) == '\\') { - // skip the escaped char - ++wordEnd; - } - ++wordEnd; - } - if (wordEnd > length) wordEnd = length; - String word = rawEvent.substring(current, wordEnd); - current += word.length(); - if (!quoted) { - word = word.trim(); - } else { - current++; // skip the trailing quote - } - // unescape stuff within the word - word = word.replace("\\\\", "\\"); - word = word.replace("\\\"", "\""); - - if (DEBUG_ROUTINE) Log.e(LOGTAG, "found '" + word + "'"); - parsed.add(word); - - // find the beginning of the next word - either of these options - int nextSpace = rawEvent.indexOf(' ', current); - int nextQuote = rawEvent.indexOf(" \"", current); - if (DEBUG_ROUTINE) { - Log.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote); - } - if (nextQuote > -1 && nextQuote <= nextSpace) { - quoted = true; - current = nextQuote + 2; - } else { - quoted = false; - if (nextSpace > -1) { - current = nextSpace + 1; - } - } // else we just start the next word after the current and read til the end - if (DEBUG_ROUTINE) { - Log.e(LOGTAG, "next loop - current=" + current - + ", length=" + length + ", quoted=" + quoted); - } - } - return parsed.toArray(new String[parsed.size()]); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonTimeoutException.java b/packages/ConnectivityT/service/src/com/android/server/NativeDaemonTimeoutException.java deleted file mode 100644 index 658f7d6264ebe..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/NativeDaemonTimeoutException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2015 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; - -/** - * An exception that indicates there was a timeout with a - * {@link NativeDaemonConnector} operation. - */ -public class NativeDaemonTimeoutException extends NativeDaemonConnectorException { - public NativeDaemonTimeoutException(String command, NativeDaemonEvent event) { - super(command, event); - } -} - diff --git a/packages/ConnectivityT/service/src/com/android/server/NsdService.java b/packages/ConnectivityT/service/src/com/android/server/NsdService.java deleted file mode 100644 index ddf6d2c4ab15b..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/NsdService.java +++ /dev/null @@ -1,1146 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.ConnectivityManager; -import android.net.LinkProperties; -import android.net.Network; -import android.net.nsd.INsdManager; -import android.net.nsd.INsdManagerCallback; -import android.net.nsd.INsdServiceConnector; -import android.net.nsd.NsdManager; -import android.net.nsd.NsdServiceInfo; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Message; -import android.os.RemoteException; -import android.os.UserHandle; -import android.util.Base64; -import android.util.Log; -import android.util.Pair; -import android.util.SparseArray; -import android.util.SparseIntArray; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; -import com.android.net.module.util.DnsSdTxtRecord; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.concurrent.CountDownLatch; - -/** - * Network Service Discovery Service handles remote service discovery operation requests by - * implementing the INsdManager interface. - * - * @hide - */ -public class NsdService extends INsdManager.Stub { - private static final String TAG = "NsdService"; - private static final String MDNS_TAG = "mDnsConnector"; - - private static final boolean DBG = true; - private static final long CLEANUP_DELAY_MS = 10000; - private static final int IFACE_IDX_ANY = 0; - - private final Context mContext; - private final NsdStateMachine mNsdStateMachine; - private final DaemonConnection mDaemon; - private final NativeCallbackReceiver mDaemonCallback; - - /** - * Clients receiving asynchronous messages - */ - private final HashMap mClients = new HashMap<>(); - - /* A map from unique id to client info */ - private final SparseArray mIdToClientInfoMap= new SparseArray<>(); - - private final long mCleanupDelayMs; - - private static final int INVALID_ID = 0; - private int mUniqueId = 1; - // The count of the connected legacy clients. - private int mLegacyClientCount = 0; - - private class NsdStateMachine extends StateMachine { - - private final DefaultState mDefaultState = new DefaultState(); - private final DisabledState mDisabledState = new DisabledState(); - private final EnabledState mEnabledState = new EnabledState(); - - @Override - protected String getWhatToString(int what) { - return NsdManager.nameOf(what); - } - - private void maybeStartDaemon() { - mDaemon.maybeStart(); - maybeScheduleStop(); - } - - private boolean isAnyRequestActive() { - return mIdToClientInfoMap.size() != 0; - } - - private void scheduleStop() { - sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs); - } - private void maybeScheduleStop() { - // The native daemon should stay alive and can't be cleanup - // if any legacy client connected. - if (!isAnyRequestActive() && mLegacyClientCount == 0) { - scheduleStop(); - } - } - - private void cancelStop() { - this.removeMessages(NsdManager.DAEMON_CLEANUP); - } - - NsdStateMachine(String name, Handler handler) { - super(name, handler); - addState(mDefaultState); - addState(mDisabledState, mDefaultState); - addState(mEnabledState, mDefaultState); - State initialState = mEnabledState; - setInitialState(initialState); - setLogRecSize(25); - } - - class DefaultState extends State { - @Override - public boolean processMessage(Message msg) { - final ClientInfo cInfo; - final int clientId = msg.arg2; - switch (msg.what) { - case NsdManager.REGISTER_CLIENT: - final Pair arg = - (Pair) msg.obj; - final INsdManagerCallback cb = arg.second; - try { - cb.asBinder().linkToDeath(arg.first, 0); - cInfo = new ClientInfo(cb); - mClients.put(arg.first, cInfo); - } catch (RemoteException e) { - Log.w(TAG, "Client " + clientId + " has already died"); - } - break; - case NsdManager.UNREGISTER_CLIENT: - final NsdServiceConnector connector = (NsdServiceConnector) msg.obj; - cInfo = mClients.remove(connector); - if (cInfo != null) { - cInfo.expungeAllRequests(); - if (cInfo.isLegacy()) { - mLegacyClientCount -= 1; - } - } - maybeScheduleStop(); - break; - case NsdManager.DISCOVER_SERVICES: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cInfo.onDiscoverServicesFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.STOP_DISCOVERY: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cInfo.onStopDiscoveryFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.REGISTER_SERVICE: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cInfo.onRegisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.UNREGISTER_SERVICE: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cInfo.onUnregisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.RESOLVE_SERVICE: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.DAEMON_CLEANUP: - mDaemon.maybeStop(); - break; - // This event should be only sent by the legacy (target SDK < S) clients. - // Mark the sending client as legacy. - case NsdManager.DAEMON_STARTUP: - cInfo = getClientInfoForReply(msg); - if (cInfo != null) { - cancelStop(); - cInfo.setLegacy(); - mLegacyClientCount += 1; - maybeStartDaemon(); - } - break; - case NsdManager.NATIVE_DAEMON_EVENT: - default: - Log.e(TAG, "Unhandled " + msg); - return NOT_HANDLED; - } - return HANDLED; - } - - private ClientInfo getClientInfoForReply(Message msg) { - final ListenerArgs args = (ListenerArgs) msg.obj; - return mClients.get(args.connector); - } - } - - class DisabledState extends State { - @Override - public void enter() { - sendNsdStateChangeBroadcast(false); - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case NsdManager.ENABLE: - transitionTo(mEnabledState); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class EnabledState extends State { - @Override - public void enter() { - sendNsdStateChangeBroadcast(true); - } - - @Override - public void exit() { - // TODO: it is incorrect to stop the daemon without expunging all requests - // and sending error callbacks to clients. - scheduleStop(); - } - - private boolean requestLimitReached(ClientInfo clientInfo) { - if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) { - if (DBG) Log.d(TAG, "Exceeded max outstanding requests " + clientInfo); - return true; - } - return false; - } - - private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) { - clientInfo.mClientIds.put(clientId, globalId); - clientInfo.mClientRequests.put(clientId, what); - mIdToClientInfoMap.put(globalId, clientInfo); - // Remove the cleanup event because here comes a new request. - cancelStop(); - } - - private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { - clientInfo.mClientIds.delete(clientId); - clientInfo.mClientRequests.delete(clientId); - mIdToClientInfoMap.remove(globalId); - maybeScheduleStop(); - } - - @Override - public boolean processMessage(Message msg) { - final ClientInfo clientInfo; - final int id; - final int clientId = msg.arg2; - final ListenerArgs args; - switch (msg.what) { - case NsdManager.DISABLE: - //TODO: cleanup clients - transitionTo(mDisabledState); - break; - case NsdManager.DISCOVER_SERVICES: - if (DBG) Log.d(TAG, "Discover services"); - args = (ListenerArgs) msg.obj; - clientInfo = mClients.get(args.connector); - - if (requestLimitReached(clientInfo)) { - clientInfo.onDiscoverServicesFailed( - clientId, NsdManager.FAILURE_MAX_LIMIT); - break; - } - - maybeStartDaemon(); - id = getUniqueId(); - if (discoverServices(id, args.serviceInfo)) { - if (DBG) { - Log.d(TAG, "Discover " + msg.arg2 + " " + id - + args.serviceInfo.getServiceType()); - } - storeRequestMap(clientId, id, clientInfo, msg.what); - clientInfo.onDiscoverServicesStarted(clientId, args.serviceInfo); - } else { - stopServiceDiscovery(id); - clientInfo.onDiscoverServicesFailed(clientId, - NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.STOP_DISCOVERY: - if (DBG) Log.d(TAG, "Stop service discovery"); - args = (ListenerArgs) msg.obj; - clientInfo = mClients.get(args.connector); - - try { - id = clientInfo.mClientIds.get(clientId); - } catch (NullPointerException e) { - clientInfo.onStopDiscoveryFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - break; - } - removeRequestMap(clientId, id, clientInfo); - if (stopServiceDiscovery(id)) { - clientInfo.onStopDiscoverySucceeded(clientId); - } else { - clientInfo.onStopDiscoveryFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.REGISTER_SERVICE: - if (DBG) Log.d(TAG, "Register service"); - args = (ListenerArgs) msg.obj; - clientInfo = mClients.get(args.connector); - if (requestLimitReached(clientInfo)) { - clientInfo.onRegisterServiceFailed( - clientId, NsdManager.FAILURE_MAX_LIMIT); - break; - } - - maybeStartDaemon(); - id = getUniqueId(); - if (registerService(id, args.serviceInfo)) { - if (DBG) Log.d(TAG, "Register " + clientId + " " + id); - storeRequestMap(clientId, id, clientInfo, msg.what); - // Return success after mDns reports success - } else { - unregisterService(id); - clientInfo.onRegisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.UNREGISTER_SERVICE: - if (DBG) Log.d(TAG, "unregister service"); - args = (ListenerArgs) msg.obj; - clientInfo = mClients.get(args.connector); - if (clientInfo == null) { - Log.e(TAG, "Unknown connector in unregistration"); - break; - } - id = clientInfo.mClientIds.get(clientId); - removeRequestMap(clientId, id, clientInfo); - if (unregisterService(id)) { - clientInfo.onUnregisterServiceSucceeded(clientId); - } else { - clientInfo.onUnregisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.RESOLVE_SERVICE: - if (DBG) Log.d(TAG, "Resolve service"); - args = (ListenerArgs) msg.obj; - clientInfo = mClients.get(args.connector); - - if (clientInfo.mResolvedService != null) { - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_ALREADY_ACTIVE); - break; - } - - maybeStartDaemon(); - id = getUniqueId(); - if (resolveService(id, args.serviceInfo)) { - clientInfo.mResolvedService = new NsdServiceInfo(); - storeRequestMap(clientId, id, clientInfo, msg.what); - } else { - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - break; - case NsdManager.NATIVE_DAEMON_EVENT: - NativeEvent event = (NativeEvent) msg.obj; - if (!handleNativeEvent(event.code, event.raw, event.cooked)) { - return NOT_HANDLED; - } - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - - private boolean handleNativeEvent(int code, String raw, String[] cooked) { - NsdServiceInfo servInfo; - int id = Integer.parseInt(cooked[1]); - ClientInfo clientInfo = mIdToClientInfoMap.get(id); - if (clientInfo == null) { - String name = NativeResponseCode.nameOf(code); - Log.e(TAG, String.format("id %d for %s has no client mapping", id, name)); - return false; - } - - /* This goes in response as msg.arg2 */ - int clientId = clientInfo.getClientId(id); - if (clientId < 0) { - // This can happen because of race conditions. For example, - // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY, - // and we may get in this situation. - String name = NativeResponseCode.nameOf(code); - Log.d(TAG, String.format( - "Notification %s for listener id %d that is no longer active", - name, id)); - return false; - } - if (DBG) { - String name = NativeResponseCode.nameOf(code); - Log.d(TAG, String.format("Native daemon message %s: %s", name, raw)); - } - switch (code) { - case NativeResponseCode.SERVICE_FOUND: - /* NNN uniqueId serviceName regType domain interfaceIdx netId */ - servInfo = new NsdServiceInfo(cooked[2], cooked[3]); - final int foundNetId; - try { - foundNetId = Integer.parseInt(cooked[6]); - } catch (NumberFormatException e) { - Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]); - break; - } - if (foundNetId == 0L) { - // Ignore services that do not have a Network: they are not usable - // by apps, as they would need privileged permissions to use - // interfaces that do not have an associated Network. - break; - } - servInfo.setNetwork(new Network(foundNetId)); - clientInfo.onServiceFound(clientId, servInfo); - break; - case NativeResponseCode.SERVICE_LOST: - /* NNN uniqueId serviceName regType domain interfaceIdx netId */ - final int lostNetId; - try { - lostNetId = Integer.parseInt(cooked[6]); - } catch (NumberFormatException e) { - Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]); - break; - } - servInfo = new NsdServiceInfo(cooked[2], cooked[3]); - // The network could be null if it was torn down when the service is lost - // TODO: avoid returning null in that case, possibly by remembering found - // services on the same interface index and their network at the time - servInfo.setNetwork(lostNetId == 0 ? null : new Network(lostNetId)); - clientInfo.onServiceLost(clientId, servInfo); - break; - case NativeResponseCode.SERVICE_DISCOVERY_FAILED: - /* NNN uniqueId errorCode */ - clientInfo.onDiscoverServicesFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - break; - case NativeResponseCode.SERVICE_REGISTERED: - /* NNN regId serviceName regType */ - servInfo = new NsdServiceInfo(cooked[2], null); - clientInfo.onRegisterServiceSucceeded(clientId, servInfo); - break; - case NativeResponseCode.SERVICE_REGISTRATION_FAILED: - /* NNN regId errorCode */ - clientInfo.onRegisterServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - break; - case NativeResponseCode.SERVICE_UPDATED: - /* NNN regId */ - break; - case NativeResponseCode.SERVICE_UPDATE_FAILED: - /* NNN regId errorCode */ - break; - case NativeResponseCode.SERVICE_RESOLVED: - /* NNN resolveId fullName hostName port txtlen txtdata interfaceIdx */ - int index = 0; - while (index < cooked[2].length() && cooked[2].charAt(index) != '.') { - if (cooked[2].charAt(index) == '\\') { - ++index; - } - ++index; - } - if (index >= cooked[2].length()) { - Log.e(TAG, "Invalid service found " + raw); - break; - } - - String name = cooked[2].substring(0, index); - String rest = cooked[2].substring(index); - String type = rest.replace(".local.", ""); - - name = unescape(name); - - clientInfo.mResolvedService.setServiceName(name); - clientInfo.mResolvedService.setServiceType(type); - clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); - clientInfo.mResolvedService.setTxtRecords(cooked[6]); - // Network will be added after SERVICE_GET_ADDR_SUCCESS - - stopResolveService(id); - removeRequestMap(clientId, id, clientInfo); - - int id2 = getUniqueId(); - if (getAddrInfo(id2, cooked[3], cooked[7] /* interfaceIdx */)) { - storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); - } else { - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - clientInfo.mResolvedService = null; - } - break; - case NativeResponseCode.SERVICE_RESOLUTION_FAILED: - /* NNN resolveId errorCode */ - stopResolveService(id); - removeRequestMap(clientId, id, clientInfo); - clientInfo.mResolvedService = null; - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - break; - case NativeResponseCode.SERVICE_GET_ADDR_FAILED: - /* NNN resolveId errorCode */ - stopGetAddrInfo(id); - removeRequestMap(clientId, id, clientInfo); - clientInfo.mResolvedService = null; - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - break; - case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS: - /* NNN resolveId hostname ttl addr interfaceIdx netId */ - Network network = null; - try { - final int netId = Integer.parseInt(cooked[6]); - network = netId == 0L ? null : new Network(netId); - } catch (NumberFormatException e) { - Log.wtf(TAG, "Invalid network in GET_ADDR_SUCCESS: " + cooked[6], e); - } - - InetAddress serviceHost = null; - try { - serviceHost = InetAddress.getByName(cooked[4]); - } catch (UnknownHostException e) { - Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e); - } - - // If the resolved service is on an interface without a network, consider it - // as a failure: it would not be usable by apps as they would need - // privileged permissions. - if (network != null && serviceHost != null) { - clientInfo.mResolvedService.setHost(serviceHost); - clientInfo.mResolvedService.setNetwork(network); - clientInfo.onResolveServiceSucceeded( - clientId, clientInfo.mResolvedService); - } else { - clientInfo.onResolveServiceFailed( - clientId, NsdManager.FAILURE_INTERNAL_ERROR); - } - stopGetAddrInfo(id); - removeRequestMap(clientId, id, clientInfo); - clientInfo.mResolvedService = null; - break; - default: - return false; - } - return true; - } - } - } - - private String unescape(String s) { - StringBuilder sb = new StringBuilder(s.length()); - for (int i = 0; i < s.length(); ++i) { - char c = s.charAt(i); - if (c == '\\') { - if (++i >= s.length()) { - Log.e(TAG, "Unexpected end of escape sequence in: " + s); - break; - } - c = s.charAt(i); - if (c != '.' && c != '\\') { - if (i + 2 >= s.length()) { - Log.e(TAG, "Unexpected end of escape sequence in: " + s); - break; - } - c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0')); - i += 2; - } - } - sb.append(c); - } - return sb.toString(); - } - - @VisibleForTesting - NsdService(Context ctx, Handler handler, DaemonConnectionSupplier fn, long cleanupDelayMs) { - mCleanupDelayMs = cleanupDelayMs; - mContext = ctx; - mNsdStateMachine = new NsdStateMachine(TAG, handler); - mNsdStateMachine.start(); - mDaemonCallback = new NativeCallbackReceiver(); - mDaemon = fn.get(mDaemonCallback); - } - - public static NsdService create(Context context) throws InterruptedException { - HandlerThread thread = new HandlerThread(TAG); - thread.start(); - Handler handler = new Handler(thread.getLooper()); - NsdService service = - new NsdService(context, handler, DaemonConnection::new, CLEANUP_DELAY_MS); - service.mDaemonCallback.awaitConnection(); - return service; - } - - @Override - public INsdServiceConnector connect(INsdManagerCallback cb) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService"); - final INsdServiceConnector connector = new NsdServiceConnector(); - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.REGISTER_CLIENT, new Pair<>(connector, cb))); - return connector; - } - - private static class ListenerArgs { - public final NsdServiceConnector connector; - public final NsdServiceInfo serviceInfo; - ListenerArgs(NsdServiceConnector connector, NsdServiceInfo serviceInfo) { - this.connector = connector; - this.serviceInfo = serviceInfo; - } - } - - private class NsdServiceConnector extends INsdServiceConnector.Stub - implements IBinder.DeathRecipient { - @Override - public void registerService(int listenerKey, NsdServiceInfo serviceInfo) { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.REGISTER_SERVICE, 0, listenerKey, - new ListenerArgs(this, serviceInfo))); - } - - @Override - public void unregisterService(int listenerKey) { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.UNREGISTER_SERVICE, 0, listenerKey, - new ListenerArgs(this, null))); - } - - @Override - public void discoverServices(int listenerKey, NsdServiceInfo serviceInfo) { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.DISCOVER_SERVICES, 0, listenerKey, - new ListenerArgs(this, serviceInfo))); - } - - @Override - public void stopDiscovery(int listenerKey) { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.STOP_DISCOVERY, 0, listenerKey, new ListenerArgs(this, null))); - } - - @Override - public void resolveService(int listenerKey, NsdServiceInfo serviceInfo) { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.RESOLVE_SERVICE, 0, listenerKey, - new ListenerArgs(this, serviceInfo))); - } - - @Override - public void startDaemon() { - mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( - NsdManager.DAEMON_STARTUP, new ListenerArgs(this, null))); - } - - @Override - public void binderDied() { - mNsdStateMachine.sendMessage( - mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_CLIENT, this)); - } - } - - private void sendNsdStateChangeBroadcast(boolean isEnabled) { - final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - int nsdState = isEnabled ? NsdManager.NSD_STATE_ENABLED : NsdManager.NSD_STATE_DISABLED; - intent.putExtra(NsdManager.EXTRA_NSD_STATE, nsdState); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - private int getUniqueId() { - if (++mUniqueId == INVALID_ID) return ++mUniqueId; - return mUniqueId; - } - - /* These should be in sync with system/netd/server/ResponseCode.h */ - static final class NativeResponseCode { - public static final int SERVICE_DISCOVERY_FAILED = 602; - public static final int SERVICE_FOUND = 603; - public static final int SERVICE_LOST = 604; - - public static final int SERVICE_REGISTRATION_FAILED = 605; - public static final int SERVICE_REGISTERED = 606; - - public static final int SERVICE_RESOLUTION_FAILED = 607; - public static final int SERVICE_RESOLVED = 608; - - public static final int SERVICE_UPDATED = 609; - public static final int SERVICE_UPDATE_FAILED = 610; - - public static final int SERVICE_GET_ADDR_FAILED = 611; - public static final int SERVICE_GET_ADDR_SUCCESS = 612; - - private static final SparseArray CODE_NAMES = new SparseArray<>(); - static { - CODE_NAMES.put(SERVICE_DISCOVERY_FAILED, "SERVICE_DISCOVERY_FAILED"); - CODE_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND"); - CODE_NAMES.put(SERVICE_LOST, "SERVICE_LOST"); - CODE_NAMES.put(SERVICE_REGISTRATION_FAILED, "SERVICE_REGISTRATION_FAILED"); - CODE_NAMES.put(SERVICE_REGISTERED, "SERVICE_REGISTERED"); - CODE_NAMES.put(SERVICE_RESOLUTION_FAILED, "SERVICE_RESOLUTION_FAILED"); - CODE_NAMES.put(SERVICE_RESOLVED, "SERVICE_RESOLVED"); - CODE_NAMES.put(SERVICE_UPDATED, "SERVICE_UPDATED"); - CODE_NAMES.put(SERVICE_UPDATE_FAILED, "SERVICE_UPDATE_FAILED"); - CODE_NAMES.put(SERVICE_GET_ADDR_FAILED, "SERVICE_GET_ADDR_FAILED"); - CODE_NAMES.put(SERVICE_GET_ADDR_SUCCESS, "SERVICE_GET_ADDR_SUCCESS"); - } - - static String nameOf(int code) { - String name = CODE_NAMES.get(code); - if (name == null) { - return Integer.toString(code); - } - return name; - } - } - - private class NativeEvent { - final int code; - final String raw; - final String[] cooked; - - NativeEvent(int code, String raw, String[] cooked) { - this.code = code; - this.raw = raw; - this.cooked = cooked; - } - } - - class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks { - private final CountDownLatch connected = new CountDownLatch(1); - - public void awaitConnection() throws InterruptedException { - connected.await(); - } - - @Override - public void onDaemonConnected() { - connected.countDown(); - } - - @Override - public boolean onCheckHoldWakeLock(int code) { - return false; - } - - @Override - public boolean onEvent(int code, String raw, String[] cooked) { - // TODO: NDC translates a message to a callback, we could enhance NDC to - // directly interact with a state machine through messages - NativeEvent event = new NativeEvent(code, raw, cooked); - mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event); - return true; - } - } - - interface DaemonConnectionSupplier { - DaemonConnection get(NativeCallbackReceiver callback); - } - - @VisibleForTesting - public static class DaemonConnection { - final NativeDaemonConnector mNativeConnector; - boolean mIsStarted = false; - - DaemonConnection(NativeCallbackReceiver callback) { - mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null); - new Thread(mNativeConnector, MDNS_TAG).start(); - } - - /** - * Executes the specified cmd on the daemon. - */ - public boolean execute(Object... args) { - if (DBG) { - Log.d(TAG, "mdnssd " + Arrays.toString(args)); - } - try { - mNativeConnector.execute("mdnssd", args); - } catch (NativeDaemonConnectorException e) { - Log.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e); - return false; - } - return true; - } - - /** - * Starts the daemon if it is not already started. - */ - public void maybeStart() { - if (mIsStarted) { - return; - } - execute("start-service"); - mIsStarted = true; - } - - /** - * Stops the daemon if it is started. - */ - public void maybeStop() { - if (!mIsStarted) { - return; - } - execute("stop-service"); - mIsStarted = false; - } - } - - private boolean registerService(int regId, NsdServiceInfo service) { - if (DBG) { - Log.d(TAG, "registerService: " + regId + " " + service); - } - String name = service.getServiceName(); - String type = service.getServiceType(); - int port = service.getPort(); - byte[] textRecord = service.getTxtRecord(); - String record = Base64.encodeToString(textRecord, Base64.DEFAULT).replace("\n", ""); - return mDaemon.execute("register", regId, name, type, port, record); - } - - private boolean unregisterService(int regId) { - return mDaemon.execute("stop-register", regId); - } - - private boolean updateService(int regId, DnsSdTxtRecord t) { - if (t == null) { - return false; - } - return mDaemon.execute("update", regId, t.size(), t.getRawData()); - } - - private boolean discoverServices(int discoveryId, NsdServiceInfo serviceInfo) { - final Network network = serviceInfo.getNetwork(); - final int discoverInterface = getNetworkInterfaceIndex(network); - if (network != null && discoverInterface == IFACE_IDX_ANY) { - Log.e(TAG, "Interface to discover service on not found"); - return false; - } - return mDaemon.execute("discover", discoveryId, serviceInfo.getServiceType(), - discoverInterface); - } - - private boolean stopServiceDiscovery(int discoveryId) { - return mDaemon.execute("stop-discover", discoveryId); - } - - private boolean resolveService(int resolveId, NsdServiceInfo service) { - final String name = service.getServiceName(); - final String type = service.getServiceType(); - final Network network = service.getNetwork(); - final int resolveInterface = getNetworkInterfaceIndex(network); - if (network != null && resolveInterface == IFACE_IDX_ANY) { - Log.e(TAG, "Interface to resolve service on not found"); - return false; - } - return mDaemon.execute("resolve", resolveId, name, type, "local.", resolveInterface); - } - - /** - * Guess the interface to use to resolve or discover a service on a specific network. - * - * This is an imperfect guess, as for example the network may be gone or not yet fully - * registered. This is fine as failing is correct if the network is gone, and a client - * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also - * this is to support the legacy mdnsresponder implementation, which historically resolved - * services on an unspecified network. - */ - private int getNetworkInterfaceIndex(Network network) { - if (network == null) return IFACE_IDX_ANY; - - final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); - if (cm == null) { - Log.wtf(TAG, "No ConnectivityManager for resolveService"); - return IFACE_IDX_ANY; - } - final LinkProperties lp = cm.getLinkProperties(network); - if (lp == null) return IFACE_IDX_ANY; - - // Only resolve on non-stacked interfaces - final NetworkInterface iface; - try { - iface = NetworkInterface.getByName(lp.getInterfaceName()); - } catch (SocketException e) { - Log.e(TAG, "Error querying interface", e); - return IFACE_IDX_ANY; - } - - if (iface == null) { - Log.e(TAG, "Interface not found: " + lp.getInterfaceName()); - return IFACE_IDX_ANY; - } - - return iface.getIndex(); - } - - private boolean stopResolveService(int resolveId) { - return mDaemon.execute("stop-resolve", resolveId); - } - - private boolean getAddrInfo(int resolveId, String hostname, String interfaceIdx) { - // interfaceIdx is always obtained (as string) from the service resolved callback - return mDaemon.execute("getaddrinfo", resolveId, hostname, interfaceIdx); - } - - private boolean stopGetAddrInfo(int resolveId) { - return mDaemon.execute("stop-getaddrinfo", resolveId); - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump " + TAG - + " due to missing android.permission.DUMP permission"); - return; - } - - for (ClientInfo client : mClients.values()) { - pw.println("Client Info"); - pw.println(client); - } - - mNsdStateMachine.dump(fd, pw, args); - } - - /* Information tracked per client */ - private class ClientInfo { - - private static final int MAX_LIMIT = 10; - private final INsdManagerCallback mCb; - /* Remembers a resolved service until getaddrinfo completes */ - private NsdServiceInfo mResolvedService; - - /* A map from client id to unique id sent to mDns */ - private final SparseIntArray mClientIds = new SparseIntArray(); - - /* A map from client id to the type of the request we had received */ - private final SparseIntArray mClientRequests = new SparseIntArray(); - - // The target SDK of this client < Build.VERSION_CODES.S - private boolean mIsLegacy = false; - - private ClientInfo(INsdManagerCallback cb) { - mCb = cb; - if (DBG) Log.d(TAG, "New client"); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("mResolvedService ").append(mResolvedService).append("\n"); - sb.append("mIsLegacy ").append(mIsLegacy).append("\n"); - for(int i = 0; i< mClientIds.size(); i++) { - int clientID = mClientIds.keyAt(i); - sb.append("clientId ").append(clientID). - append(" mDnsId ").append(mClientIds.valueAt(i)). - append(" type ").append(mClientRequests.get(clientID)).append("\n"); - } - return sb.toString(); - } - - private boolean isLegacy() { - return mIsLegacy; - } - - private void setLegacy() { - mIsLegacy = true; - } - - // Remove any pending requests from the global map when we get rid of a client, - // and send cancellations to the daemon. - private void expungeAllRequests() { - int globalId, clientId, i; - // TODO: to keep handler responsive, do not clean all requests for that client at once. - for (i = 0; i < mClientIds.size(); i++) { - clientId = mClientIds.keyAt(i); - globalId = mClientIds.valueAt(i); - mIdToClientInfoMap.remove(globalId); - if (DBG) { - Log.d(TAG, "Terminating client-ID " + clientId - + " global-ID " + globalId + " type " + mClientRequests.get(clientId)); - } - switch (mClientRequests.get(clientId)) { - case NsdManager.DISCOVER_SERVICES: - stopServiceDiscovery(globalId); - break; - case NsdManager.RESOLVE_SERVICE: - stopResolveService(globalId); - break; - case NsdManager.REGISTER_SERVICE: - unregisterService(globalId); - break; - default: - break; - } - } - mClientIds.clear(); - mClientRequests.clear(); - } - - // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id, - // return the corresponding listener id. mDnsClient id is also called a global id. - private int getClientId(final int globalId) { - int idx = mClientIds.indexOfValue(globalId); - if (idx < 0) { - return idx; - } - return mClientIds.keyAt(idx); - } - - void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) { - try { - mCb.onDiscoverServicesStarted(listenerKey, info); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onDiscoverServicesStarted", e); - } - } - - void onDiscoverServicesFailed(int listenerKey, int error) { - try { - mCb.onDiscoverServicesFailed(listenerKey, error); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onDiscoverServicesFailed", e); - } - } - - void onServiceFound(int listenerKey, NsdServiceInfo info) { - try { - mCb.onServiceFound(listenerKey, info); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onServiceFound(", e); - } - } - - void onServiceLost(int listenerKey, NsdServiceInfo info) { - try { - mCb.onServiceLost(listenerKey, info); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onServiceLost(", e); - } - } - - void onStopDiscoveryFailed(int listenerKey, int error) { - try { - mCb.onStopDiscoveryFailed(listenerKey, error); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onStopDiscoveryFailed", e); - } - } - - void onStopDiscoverySucceeded(int listenerKey) { - try { - mCb.onStopDiscoverySucceeded(listenerKey); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onStopDiscoverySucceeded", e); - } - } - - void onRegisterServiceFailed(int listenerKey, int error) { - try { - mCb.onRegisterServiceFailed(listenerKey, error); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onRegisterServiceFailed", e); - } - } - - void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) { - try { - mCb.onRegisterServiceSucceeded(listenerKey, info); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onRegisterServiceSucceeded", e); - } - } - - void onUnregisterServiceFailed(int listenerKey, int error) { - try { - mCb.onUnregisterServiceFailed(listenerKey, error); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onUnregisterServiceFailed", e); - } - } - - void onUnregisterServiceSucceeded(int listenerKey) { - try { - mCb.onUnregisterServiceSucceeded(listenerKey); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onUnregisterServiceSucceeded", e); - } - } - - void onResolveServiceFailed(int listenerKey, int error) { - try { - mCb.onResolveServiceFailed(listenerKey, error); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onResolveServiceFailed", e); - } - } - - void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) { - try { - mCb.onResolveServiceSucceeded(listenerKey, info); - } catch (RemoteException e) { - Log.e(TAG, "Error calling onResolveServiceSucceeded", e); - } - } - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java b/packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java deleted file mode 100644 index 25c88eb6bdb27..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/BpfInterfaceMapUpdater.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import android.content.Context; -import android.net.INetd; -import android.os.Handler; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.system.ErrnoException; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.BaseNetdUnsolicitedEventListener; -import com.android.net.module.util.BpfMap; -import com.android.net.module.util.IBpfMap; -import com.android.net.module.util.InterfaceParams; -import com.android.net.module.util.Struct.U32; - -/** - * Monitor interface added (without removed) and right interface name and its index to bpf map. - */ -public class BpfInterfaceMapUpdater { - private static final String TAG = BpfInterfaceMapUpdater.class.getSimpleName(); - // This is current path but may be changed soon. - private static final String IFACE_INDEX_NAME_MAP_PATH = - "/sys/fs/bpf/map_netd_iface_index_name_map"; - private final IBpfMap mBpfMap; - private final INetd mNetd; - private final Handler mHandler; - private final Dependencies mDeps; - - public BpfInterfaceMapUpdater(Context ctx, Handler handler) { - this(ctx, handler, new Dependencies()); - } - - @VisibleForTesting - public BpfInterfaceMapUpdater(Context ctx, Handler handler, Dependencies deps) { - mDeps = deps; - mBpfMap = deps.getInterfaceMap(); - mNetd = deps.getINetd(ctx); - mHandler = handler; - } - - /** - * Dependencies of BpfInerfaceMapUpdater, for injection in tests. - */ - @VisibleForTesting - public static class Dependencies { - /** Create BpfMap for updating interface and index mapping. */ - public IBpfMap getInterfaceMap() { - try { - return new BpfMap<>(IFACE_INDEX_NAME_MAP_PATH, BpfMap.BPF_F_RDWR, - U32.class, InterfaceMapValue.class); - } catch (ErrnoException e) { - Log.e(TAG, "Cannot create interface map: " + e); - return null; - } - } - - /** Get InterfaceParams for giving interface name. */ - public InterfaceParams getInterfaceParams(String ifaceName) { - return InterfaceParams.getByName(ifaceName); - } - - /** Get INetd binder object. */ - public INetd getINetd(Context ctx) { - return INetd.Stub.asInterface((IBinder) ctx.getSystemService(Context.NETD_SERVICE)); - } - } - - /** - * Start listening interface update event. - * Query current interface names before listening. - */ - public void start() { - mHandler.post(() -> { - if (mBpfMap == null) { - Log.wtf(TAG, "Fail to start: Null bpf map"); - return; - } - - try { - // TODO: use a NetlinkMonitor and listen for RTM_NEWLINK messages instead. - mNetd.registerUnsolicitedEventListener(new InterfaceChangeObserver()); - } catch (RemoteException e) { - Log.wtf(TAG, "Unable to register netd UnsolicitedEventListener, " + e); - } - - final String[] ifaces; - try { - // TODO: use a netlink dump to get the current interface list. - ifaces = mNetd.interfaceGetList(); - } catch (RemoteException | ServiceSpecificException e) { - Log.wtf(TAG, "Unable to query interface names by netd, " + e); - return; - } - - for (String ifaceName : ifaces) { - addInterface(ifaceName); - } - }); - } - - private void addInterface(String ifaceName) { - final InterfaceParams iface = mDeps.getInterfaceParams(ifaceName); - if (iface == null) { - Log.e(TAG, "Unable to get InterfaceParams for " + ifaceName); - return; - } - - try { - mBpfMap.updateEntry(new U32(iface.index), new InterfaceMapValue(ifaceName)); - } catch (ErrnoException e) { - Log.e(TAG, "Unable to update entry for " + ifaceName + ", " + e); - } - } - - private class InterfaceChangeObserver extends BaseNetdUnsolicitedEventListener { - @Override - public void onInterfaceAdded(String ifName) { - mHandler.post(() -> addInterface(ifName)); - } - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java deleted file mode 100644 index 443e5b38475e4..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapKey.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * Key for cookie tag map. - */ -public class CookieTagMapKey extends Struct { - @Field(order = 0, type = Type.S64) - public final long socketCookie; - - public CookieTagMapKey(final long socketCookie) { - this.socketCookie = socketCookie; - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java deleted file mode 100644 index 93b9195f92da3..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/CookieTagMapValue.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * Value for cookie tag map. - */ -public class CookieTagMapValue extends Struct { - @Field(order = 0, type = Type.U32) - public final long uid; - - @Field(order = 1, type = Type.U32) - public final long tag; - - public CookieTagMapValue(final long uid, final long tag) { - this.uid = uid; - this.tag = tag; - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/DelayedDiskWrite.java b/packages/ConnectivityT/service/src/com/android/server/net/DelayedDiskWrite.java deleted file mode 100644 index 35dc4557252cd..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/DelayedDiskWrite.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2014 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; - -import android.os.Handler; -import android.os.HandlerThread; -import android.text.TextUtils; -import android.util.Log; - -import java.io.BufferedOutputStream; -import java.io.DataOutputStream; -import java.io.FileOutputStream; -import java.io.IOException; - -/** - * This class provides APIs to do a delayed data write to a given {@link OutputStream}. - */ -public class DelayedDiskWrite { - private static final String TAG = "DelayedDiskWrite"; - - private HandlerThread mDiskWriteHandlerThread; - private Handler mDiskWriteHandler; - /* Tracks multiple writes on the same thread */ - private int mWriteSequence = 0; - - /** - * Used to do a delayed data write to a given {@link OutputStream}. - */ - public interface Writer { - /** - * write data to a given {@link OutputStream}. - */ - void onWriteCalled(DataOutputStream out) throws IOException; - } - - /** - * Do a delayed data write to a given output stream opened from filePath. - */ - public void write(final String filePath, final Writer w) { - write(filePath, w, true); - } - - /** - * Do a delayed data write to a given output stream opened from filePath. - */ - public void write(final String filePath, final Writer w, final boolean open) { - if (TextUtils.isEmpty(filePath)) { - throw new IllegalArgumentException("empty file path"); - } - - /* Do a delayed write to disk on a separate handler thread */ - synchronized (this) { - if (++mWriteSequence == 1) { - mDiskWriteHandlerThread = new HandlerThread("DelayedDiskWriteThread"); - mDiskWriteHandlerThread.start(); - mDiskWriteHandler = new Handler(mDiskWriteHandlerThread.getLooper()); - } - } - - mDiskWriteHandler.post(new Runnable() { - @Override - public void run() { - doWrite(filePath, w, open); - } - }); - } - - private void doWrite(String filePath, Writer w, boolean open) { - DataOutputStream out = null; - try { - if (open) { - out = new DataOutputStream(new BufferedOutputStream( - new FileOutputStream(filePath))); - } - w.onWriteCalled(out); - } catch (IOException e) { - loge("Error writing data file " + filePath); - } finally { - if (out != null) { - try { - out.close(); - } catch (Exception e) { } - } - - // Quit if no more writes sent - synchronized (this) { - if (--mWriteSequence == 0) { - mDiskWriteHandler.getLooper().quit(); - mDiskWriteHandler = null; - mDiskWriteHandlerThread = null; - } - } - } - } - - private void loge(String s) { - Log.e(TAG, s); - } -} - diff --git a/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java deleted file mode 100644 index 42c0044e666fc..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/InterfaceMapValue.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * The value of bpf interface index map which is used for NetworkStatsService. - */ -public class InterfaceMapValue extends Struct { - @Field(order = 0, type = Type.ByteArray, arraysize = 16) - public final byte[] interfaceName; - - public InterfaceMapValue(String iface) { - final byte[] ifaceArray = iface.getBytes(); - interfaceName = new byte[16]; - // All array bytes after the interface name, if any, must be 0. - System.arraycopy(ifaceArray, 0, interfaceName, 0, ifaceArray.length); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java b/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java deleted file mode 100644 index 3a9a544155373..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/IpConfigStore.java +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (C) 2014 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; - -import android.net.InetAddresses; -import android.net.IpConfiguration; -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; -import android.net.LinkAddress; -import android.net.ProxyInfo; -import android.net.StaticIpConfiguration; -import android.net.Uri; -import android.util.ArrayMap; -import android.util.Log; -import android.util.SparseArray; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.ProxyUtils; - -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.EOFException; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; - -/** - * This class provides an API to store and manage L3 network IP configuration. - */ -public class IpConfigStore { - private static final String TAG = "IpConfigStore"; - private static final boolean DBG = false; - - protected final DelayedDiskWrite mWriter; - - /* IP and proxy configuration keys */ - protected static final String ID_KEY = "id"; - protected static final String IP_ASSIGNMENT_KEY = "ipAssignment"; - protected static final String LINK_ADDRESS_KEY = "linkAddress"; - protected static final String GATEWAY_KEY = "gateway"; - protected static final String DNS_KEY = "dns"; - protected static final String PROXY_SETTINGS_KEY = "proxySettings"; - protected static final String PROXY_HOST_KEY = "proxyHost"; - protected static final String PROXY_PORT_KEY = "proxyPort"; - protected static final String PROXY_PAC_FILE = "proxyPac"; - protected static final String EXCLUSION_LIST_KEY = "exclusionList"; - protected static final String EOS = "eos"; - - protected static final int IPCONFIG_FILE_VERSION = 3; - - public IpConfigStore(DelayedDiskWrite writer) { - mWriter = writer; - } - - public IpConfigStore() { - this(new DelayedDiskWrite()); - } - - private static boolean writeConfig(DataOutputStream out, String configKey, - IpConfiguration config) throws IOException { - return writeConfig(out, configKey, config, IPCONFIG_FILE_VERSION); - } - - /** - * Write the IP configuration with the given parameters to {@link DataOutputStream}. - */ - @VisibleForTesting - public static boolean writeConfig(DataOutputStream out, String configKey, - IpConfiguration config, int version) throws IOException { - boolean written = false; - - try { - switch (config.getIpAssignment()) { - case STATIC: - out.writeUTF(IP_ASSIGNMENT_KEY); - out.writeUTF(config.getIpAssignment().toString()); - StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration(); - if (staticIpConfiguration != null) { - if (staticIpConfiguration.getIpAddress() != null) { - LinkAddress ipAddress = staticIpConfiguration.getIpAddress(); - out.writeUTF(LINK_ADDRESS_KEY); - out.writeUTF(ipAddress.getAddress().getHostAddress()); - out.writeInt(ipAddress.getPrefixLength()); - } - if (staticIpConfiguration.getGateway() != null) { - out.writeUTF(GATEWAY_KEY); - out.writeInt(0); // Default route. - out.writeInt(1); // Have a gateway. - out.writeUTF(staticIpConfiguration.getGateway().getHostAddress()); - } - for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) { - out.writeUTF(DNS_KEY); - out.writeUTF(inetAddr.getHostAddress()); - } - } - written = true; - break; - case DHCP: - out.writeUTF(IP_ASSIGNMENT_KEY); - out.writeUTF(config.getIpAssignment().toString()); - written = true; - break; - case UNASSIGNED: - /* Ignore */ - break; - default: - loge("Ignore invalid ip assignment while writing"); - break; - } - - switch (config.getProxySettings()) { - case STATIC: - ProxyInfo proxyProperties = config.getHttpProxy(); - String exclusionList = ProxyUtils.exclusionListAsString( - proxyProperties.getExclusionList()); - out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.getProxySettings().toString()); - out.writeUTF(PROXY_HOST_KEY); - out.writeUTF(proxyProperties.getHost()); - out.writeUTF(PROXY_PORT_KEY); - out.writeInt(proxyProperties.getPort()); - if (exclusionList != null) { - out.writeUTF(EXCLUSION_LIST_KEY); - out.writeUTF(exclusionList); - } - written = true; - break; - case PAC: - ProxyInfo proxyPacProperties = config.getHttpProxy(); - out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.getProxySettings().toString()); - out.writeUTF(PROXY_PAC_FILE); - out.writeUTF(proxyPacProperties.getPacFileUrl().toString()); - written = true; - break; - case NONE: - out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.getProxySettings().toString()); - written = true; - break; - case UNASSIGNED: - /* Ignore */ - break; - default: - loge("Ignore invalid proxy settings while writing"); - break; - } - - if (written) { - out.writeUTF(ID_KEY); - if (version < 3) { - out.writeInt(Integer.valueOf(configKey)); - } else { - out.writeUTF(configKey); - } - } - } catch (NullPointerException e) { - loge("Failure in writing " + config + e); - } - out.writeUTF(EOS); - - return written; - } - - /** - * @deprecated use {@link #writeIpConfigurations(String, ArrayMap)} instead. - * New method uses string as network identifier which could be interface name or MAC address or - * other token. - */ - @Deprecated - public void writeIpAndProxyConfigurationsToFile(String filePath, - final SparseArray networks) { - mWriter.write(filePath, out -> { - out.writeInt(IPCONFIG_FILE_VERSION); - for (int i = 0; i < networks.size(); i++) { - writeConfig(out, String.valueOf(networks.keyAt(i)), networks.valueAt(i)); - } - }); - } - - /** - * Write the IP configuration associated to the target networks to the destination path. - */ - public void writeIpConfigurations(String filePath, - ArrayMap networks) { - mWriter.write(filePath, out -> { - out.writeInt(IPCONFIG_FILE_VERSION); - for (int i = 0; i < networks.size(); i++) { - writeConfig(out, networks.keyAt(i), networks.valueAt(i)); - } - }); - } - - /** - * Read the IP configuration from the destination path to {@link BufferedInputStream}. - */ - public static ArrayMap readIpConfigurations(String filePath) { - BufferedInputStream bufferedInputStream; - try { - bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); - } catch (FileNotFoundException e) { - // Return an empty array here because callers expect an empty array when the file is - // not present. - loge("Error opening configuration file: " + e); - return new ArrayMap<>(0); - } - return readIpConfigurations(bufferedInputStream); - } - - /** @deprecated use {@link #readIpConfigurations(String)} */ - @Deprecated - public static SparseArray readIpAndProxyConfigurations(String filePath) { - BufferedInputStream bufferedInputStream; - try { - bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); - } catch (FileNotFoundException e) { - // Return an empty array here because callers expect an empty array when the file is - // not present. - loge("Error opening configuration file: " + e); - return new SparseArray<>(); - } - return readIpAndProxyConfigurations(bufferedInputStream); - } - - /** @deprecated use {@link #readIpConfigurations(InputStream)} */ - @Deprecated - public static SparseArray readIpAndProxyConfigurations( - InputStream inputStream) { - ArrayMap networks = readIpConfigurations(inputStream); - if (networks == null) { - return null; - } - - SparseArray networksById = new SparseArray<>(); - for (int i = 0; i < networks.size(); i++) { - int id = Integer.valueOf(networks.keyAt(i)); - networksById.put(id, networks.valueAt(i)); - } - - return networksById; - } - - /** Returns a map of network identity token and {@link IpConfiguration}. */ - public static ArrayMap readIpConfigurations( - InputStream inputStream) { - ArrayMap networks = new ArrayMap<>(); - DataInputStream in = null; - try { - in = new DataInputStream(inputStream); - - int version = in.readInt(); - if (version != 3 && version != 2 && version != 1) { - loge("Bad version on IP configuration file, ignore read"); - return null; - } - - while (true) { - String uniqueToken = null; - // Default is DHCP with no proxy - IpAssignment ipAssignment = IpAssignment.DHCP; - ProxySettings proxySettings = ProxySettings.NONE; - StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); - LinkAddress linkAddress = null; - InetAddress gatewayAddress = null; - String proxyHost = null; - String pacFileUrl = null; - int proxyPort = -1; - String exclusionList = null; - String key; - final List dnsServers = new ArrayList<>(); - - do { - key = in.readUTF(); - try { - if (key.equals(ID_KEY)) { - if (version < 3) { - int id = in.readInt(); - uniqueToken = String.valueOf(id); - } else { - uniqueToken = in.readUTF(); - } - } else if (key.equals(IP_ASSIGNMENT_KEY)) { - ipAssignment = IpAssignment.valueOf(in.readUTF()); - } else if (key.equals(LINK_ADDRESS_KEY)) { - LinkAddress parsedLinkAddress = - new LinkAddress( - InetAddresses.parseNumericAddress(in.readUTF()), - in.readInt()); - if (parsedLinkAddress.getAddress() instanceof Inet4Address - && linkAddress == null) { - linkAddress = parsedLinkAddress; - } else { - loge("Non-IPv4 or duplicate address: " + parsedLinkAddress); - } - } else if (key.equals(GATEWAY_KEY)) { - LinkAddress dest = null; - InetAddress gateway = null; - if (version == 1) { - // only supported default gateways - leave the dest/prefix empty - gateway = InetAddresses.parseNumericAddress(in.readUTF()); - if (gatewayAddress == null) { - gatewayAddress = gateway; - } else { - loge("Duplicate gateway: " + gateway.getHostAddress()); - } - } else { - if (in.readInt() == 1) { - dest = - new LinkAddress( - InetAddresses.parseNumericAddress(in.readUTF()), - in.readInt()); - } - if (in.readInt() == 1) { - gateway = InetAddresses.parseNumericAddress(in.readUTF()); - } - // If the destination is a default IPv4 route, use the gateway - // address unless already set. If there is no destination, assume - // it is default route and use the gateway address in all cases. - if (dest == null) { - gatewayAddress = gateway; - } else if (dest.getAddress() instanceof Inet4Address - && dest.getPrefixLength() == 0 && gatewayAddress == null) { - gatewayAddress = gateway; - } else { - loge("Non-IPv4 default or duplicate route: " - + dest.getAddress()); - } - } - } else if (key.equals(DNS_KEY)) { - dnsServers.add(InetAddresses.parseNumericAddress(in.readUTF())); - } else if (key.equals(PROXY_SETTINGS_KEY)) { - proxySettings = ProxySettings.valueOf(in.readUTF()); - } else if (key.equals(PROXY_HOST_KEY)) { - proxyHost = in.readUTF(); - } else if (key.equals(PROXY_PORT_KEY)) { - proxyPort = in.readInt(); - } else if (key.equals(PROXY_PAC_FILE)) { - pacFileUrl = in.readUTF(); - } else if (key.equals(EXCLUSION_LIST_KEY)) { - exclusionList = in.readUTF(); - } else if (key.equals(EOS)) { - break; - } else { - loge("Ignore unknown key " + key + "while reading"); - } - } catch (IllegalArgumentException e) { - loge("Ignore invalid address while reading" + e); - } - } while (true); - - staticIpConfiguration = new StaticIpConfiguration.Builder() - .setIpAddress(linkAddress) - .setGateway(gatewayAddress) - .setDnsServers(dnsServers) - .build(); - - if (uniqueToken != null) { - IpConfiguration config = new IpConfiguration(); - networks.put(uniqueToken, config); - - switch (ipAssignment) { - case STATIC: - config.setStaticIpConfiguration(staticIpConfiguration); - config.setIpAssignment(ipAssignment); - break; - case DHCP: - config.setIpAssignment(ipAssignment); - break; - case UNASSIGNED: - loge("BUG: Found UNASSIGNED IP on file, use DHCP"); - config.setIpAssignment(IpAssignment.DHCP); - break; - default: - loge("Ignore invalid ip assignment while reading."); - config.setIpAssignment(IpAssignment.UNASSIGNED); - break; - } - - switch (proxySettings) { - case STATIC: - ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort, - ProxyUtils.exclusionStringAsList(exclusionList)); - config.setProxySettings(proxySettings); - config.setHttpProxy(proxyInfo); - break; - case PAC: - ProxyInfo proxyPacProperties = - ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl)); - config.setProxySettings(proxySettings); - config.setHttpProxy(proxyPacProperties); - break; - case NONE: - config.setProxySettings(proxySettings); - break; - case UNASSIGNED: - loge("BUG: Found UNASSIGNED proxy on file, use NONE"); - config.setProxySettings(ProxySettings.NONE); - break; - default: - loge("Ignore invalid proxy settings while reading"); - config.setProxySettings(ProxySettings.UNASSIGNED); - break; - } - } else { - if (DBG) log("Missing id while parsing configuration"); - } - } - } catch (EOFException ignore) { - } catch (IOException e) { - loge("Error parsing configuration: " + e); - } finally { - if (in != null) { - try { - in.close(); - } catch (Exception e) { } - } - } - - return networks; - } - - protected static void loge(String s) { - Log.e(TAG, s); - } - - protected static void log(String s) { - Log.d(TAG, s); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java deleted file mode 100644 index 3b93f1a1905f1..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsFactory.java +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import static android.net.NetworkStats.INTERFACES_ALL; -import static android.net.NetworkStats.SET_ALL; -import static android.net.NetworkStats.TAG_ALL; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.net.NetworkStats; -import android.net.UnderlyingNetworkInfo; -import android.os.ServiceSpecificException; -import android.os.StrictMode; -import android.os.SystemClock; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ProcFileReader; -import com.android.net.module.util.CollectionUtils; -import com.android.server.BpfNetMaps; - -import libcore.io.IoUtils; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.net.ProtocolException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Creates {@link NetworkStats} instances by parsing various {@code /proc/} - * files as needed. - * - * @hide - */ -public class NetworkStatsFactory { - static { - System.loadLibrary("service-connectivity"); - } - - private static final String TAG = "NetworkStatsFactory"; - - private static final boolean USE_NATIVE_PARSING = true; - private static final boolean VALIDATE_NATIVE_STATS = false; - - /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ - private final File mStatsXtIfaceAll; - /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */ - private final File mStatsXtIfaceFmt; - /** Path to {@code /proc/net/xt_qtaguid/stats}. */ - private final File mStatsXtUid; - - private final boolean mUseBpfStats; - - private final Context mContext; - - private final BpfNetMaps mBpfNetMaps; - - /** - * Guards persistent data access in this class - * - *

In order to prevent deadlocks, critical sections protected by this lock SHALL NOT call out - * to other code that will acquire other locks within the system server. See b/134244752. - */ - private final Object mPersistentDataLock = new Object(); - - /** Set containing info about active VPNs and their underlying networks. */ - private volatile UnderlyingNetworkInfo[] mUnderlyingNetworkInfos = new UnderlyingNetworkInfo[0]; - - // A persistent snapshot of cumulative stats since device start - @GuardedBy("mPersistentDataLock") - private NetworkStats mPersistSnapshot; - - // The persistent snapshot of tun and 464xlat adjusted stats since device start - @GuardedBy("mPersistentDataLock") - private NetworkStats mTunAnd464xlatAdjustedStats; - - /** - * (Stacked interface) -> (base interface) association for all connected ifaces since boot. - * - * Because counters must never roll backwards, once a given interface is stacked on top of an - * underlying interface, the stacked interface can never be stacked on top of - * another interface. */ - private final ConcurrentHashMap mStackedIfaces - = new ConcurrentHashMap<>(); - - /** Informs the factory of a new stacked interface. */ - public void noteStackedIface(String stackedIface, String baseIface) { - if (stackedIface != null && baseIface != null) { - mStackedIfaces.put(stackedIface, baseIface); - } - } - - /** - * Set active VPN information for data usage migration purposes - * - *

Traffic on TUN-based VPNs inherently all appear to be originated from the VPN providing - * app's UID. This method is used to support migration of VPN data usage, ensuring data is - * accurately billed to the real owner of the traffic. - * - * @param vpnArray The snapshot of the currently-running VPNs. - */ - public void updateUnderlyingNetworkInfos(UnderlyingNetworkInfo[] vpnArray) { - mUnderlyingNetworkInfos = vpnArray.clone(); - } - - /** - * Get a set of interfaces containing specified ifaces and stacked interfaces. - * - *

The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces - * on which the specified ones are stacked. Stacked interfaces are those noted with - * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method - * is called are guaranteed to be included. - */ - public String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) { - if (requiredIfaces == NetworkStats.INTERFACES_ALL) { - return null; - } - - HashSet relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces)); - // ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse - // elements as they existed upon construction exactly once, and may - // (but are not guaranteed to) reflect any modifications subsequent to construction". - // This is enough here. - for (Map.Entry entry : mStackedIfaces.entrySet()) { - if (relatedIfaces.contains(entry.getKey())) { - relatedIfaces.add(entry.getValue()); - } else if (relatedIfaces.contains(entry.getValue())) { - relatedIfaces.add(entry.getKey()); - } - } - - String[] outArray = new String[relatedIfaces.size()]; - return relatedIfaces.toArray(outArray); - } - - /** - * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. - * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) - */ - public void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces); - } - - public NetworkStatsFactory(@NonNull Context ctx) { - this(ctx, new File("/proc/"), true); - } - - @VisibleForTesting - public NetworkStatsFactory(@NonNull Context ctx, File procRoot, boolean useBpfStats) { - mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); - mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); - mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); - mUseBpfStats = useBpfStats; - mBpfNetMaps = new BpfNetMaps(); - synchronized (mPersistentDataLock) { - mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); - mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1); - } - mContext = ctx; - } - - public NetworkStats readBpfNetworkStatsDev() throws IOException { - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); - if (nativeReadNetworkStatsDev(stats) != 0) { - throw new IOException("Failed to parse bpf iface stats"); - } - return stats; - } - - /** - * Parse and return interface-level summary {@link NetworkStats} measured - * using {@code /proc/net/dev} style hooks, which may include non IP layer - * traffic. Values monotonically increase since device boot, and may include - * details about inactive interfaces. - * - * @throws IllegalStateException when problem parsing stats. - */ - public NetworkStats readNetworkStatsSummaryDev() throws IOException { - - // Return xt_bpf stats if switched to bpf module. - if (mUseBpfStats) - return readBpfNetworkStatsDev(); - - final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); - - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - - ProcFileReader reader = null; - try { - reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceAll)); - - while (reader.hasMoreData()) { - entry.iface = reader.nextString(); - entry.uid = UID_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - - final boolean active = reader.nextInt() != 0; - - // always include snapshot values - entry.rxBytes = reader.nextLong(); - entry.rxPackets = reader.nextLong(); - entry.txBytes = reader.nextLong(); - entry.txPackets = reader.nextLong(); - - // fold in active numbers, but only when active - if (active) { - entry.rxBytes += reader.nextLong(); - entry.rxPackets += reader.nextLong(); - entry.txBytes += reader.nextLong(); - entry.txPackets += reader.nextLong(); - } - - stats.insertEntry(entry); - reader.finishLine(); - } - } catch (NullPointerException|NumberFormatException e) { - throw protocolExceptionWithCause("problem parsing stats", e); - } finally { - IoUtils.closeQuietly(reader); - StrictMode.setThreadPolicy(savedPolicy); - } - return stats; - } - - /** - * Parse and return interface-level summary {@link NetworkStats}. Designed - * to return only IP layer traffic. Values monotonically increase since - * device boot, and may include details about inactive interfaces. - * - * @throws IllegalStateException when problem parsing stats. - */ - public NetworkStats readNetworkStatsSummaryXt() throws IOException { - - // Return xt_bpf stats if qtaguid module is replaced. - if (mUseBpfStats) - return readBpfNetworkStatsDev(); - - final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); - - // return null when kernel doesn't support - if (!mStatsXtIfaceFmt.exists()) return null; - - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - - ProcFileReader reader = null; - try { - // open and consume header line - reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceFmt)); - reader.finishLine(); - - while (reader.hasMoreData()) { - entry.iface = reader.nextString(); - entry.uid = UID_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - - entry.rxBytes = reader.nextLong(); - entry.rxPackets = reader.nextLong(); - entry.txBytes = reader.nextLong(); - entry.txPackets = reader.nextLong(); - - stats.insertEntry(entry); - reader.finishLine(); - } - } catch (NullPointerException|NumberFormatException e) { - throw protocolExceptionWithCause("problem parsing stats", e); - } finally { - IoUtils.closeQuietly(reader); - StrictMode.setThreadPolicy(savedPolicy); - } - return stats; - } - - public NetworkStats readNetworkStatsDetail() throws IOException { - return readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL); - } - - @GuardedBy("mPersistentDataLock") - private void requestSwapActiveStatsMapLocked() throws IOException { - try { - // Do a active map stats swap. Once the swap completes, this code - // can read and clean the inactive map without races. - mBpfNetMaps.swapActiveStatsMap(); - } catch (ServiceSpecificException e) { - throw new IOException(e); - } - } - - /** - * Reads the detailed UID stats based on the provided parameters - * - * @param limitUid the UID to limit this query to - * @param limitIfaces the interfaces to limit this query to. Use {@link - * NetworkStats.INTERFACES_ALL} to select all interfaces - * @param limitTag the tags to limit this query to - * @return the NetworkStats instance containing network statistics at the present time. - */ - public NetworkStats readNetworkStatsDetail( - int limitUid, String[] limitIfaces, int limitTag) throws IOException { - // In order to prevent deadlocks, anything protected by this lock MUST NOT call out to other - // code that will acquire other locks within the system server. See b/134244752. - synchronized (mPersistentDataLock) { - // Take a reference. If this gets swapped out, we still have the old reference. - final UnderlyingNetworkInfo[] vpnArray = mUnderlyingNetworkInfos; - // Take a defensive copy. mPersistSnapshot is mutated in some cases below - final NetworkStats prev = mPersistSnapshot.clone(); - - if (USE_NATIVE_PARSING) { - final NetworkStats stats = - new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */); - if (mUseBpfStats) { - requestSwapActiveStatsMapLocked(); - // Stats are always read from the inactive map, so they must be read after the - // swap - if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, - INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) { - throw new IOException("Failed to parse network stats"); - } - - // BPF stats are incremental; fold into mPersistSnapshot. - mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime()); - mPersistSnapshot.combineAllValues(stats); - } else { - if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, - INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) { - throw new IOException("Failed to parse network stats"); - } - if (VALIDATE_NATIVE_STATS) { - final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, - UID_ALL, INTERFACES_ALL, TAG_ALL); - assertEquals(javaStats, stats); - } - - mPersistSnapshot = stats; - } - } else { - mPersistSnapshot = javaReadNetworkStatsDetail(mStatsXtUid, UID_ALL, INTERFACES_ALL, - TAG_ALL); - } - - NetworkStats adjustedStats = adjustForTunAnd464Xlat(mPersistSnapshot, prev, vpnArray); - - // Filter return values - adjustedStats.filter(limitUid, limitIfaces, limitTag); - return adjustedStats; - } - } - - @GuardedBy("mPersistentDataLock") - private NetworkStats adjustForTunAnd464Xlat(NetworkStats uidDetailStats, - NetworkStats previousStats, UnderlyingNetworkInfo[] vpnArray) { - // Calculate delta from last snapshot - final NetworkStats delta = uidDetailStats.subtract(previousStats); - - // Apply 464xlat adjustments before VPN adjustments. If VPNs are using v4 on a v6 only - // network, the overhead is their fault. - // No locking here: apply464xlatAdjustments behaves fine with an add-only - // ConcurrentHashMap. - delta.apply464xlatAdjustments(mStackedIfaces); - - // Migrate data usage over a VPN to the TUN network. - for (UnderlyingNetworkInfo info : vpnArray) { - delta.migrateTun(info.getOwnerUid(), info.getInterface(), - info.getUnderlyingInterfaces()); - // Filter out debug entries as that may lead to over counting. - delta.filterDebugEntries(); - } - - // Update mTunAnd464xlatAdjustedStats with migrated delta. - mTunAnd464xlatAdjustedStats.combineAllValues(delta); - mTunAnd464xlatAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime()); - - return mTunAnd464xlatAdjustedStats.clone(); - } - - /** - * Parse and return {@link NetworkStats} with UID-level details. Values are - * expected to monotonically increase since device boot. - */ - @VisibleForTesting - public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid, - String[] limitIfaces, int limitTag) - throws IOException { - final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); - - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - - int idx = 1; - int lastIdx = 1; - - ProcFileReader reader = null; - try { - // open and consume header line - reader = new ProcFileReader(new FileInputStream(detailPath)); - reader.finishLine(); - - while (reader.hasMoreData()) { - idx = reader.nextInt(); - if (idx != lastIdx + 1) { - throw new ProtocolException( - "inconsistent idx=" + idx + " after lastIdx=" + lastIdx); - } - lastIdx = idx; - - entry.iface = reader.nextString(); - entry.tag = kernelToTag(reader.nextString()); - entry.uid = reader.nextInt(); - entry.set = reader.nextInt(); - entry.rxBytes = reader.nextLong(); - entry.rxPackets = reader.nextLong(); - entry.txBytes = reader.nextLong(); - entry.txPackets = reader.nextLong(); - - if ((limitIfaces == null || CollectionUtils.contains(limitIfaces, entry.iface)) - && (limitUid == UID_ALL || limitUid == entry.uid) - && (limitTag == TAG_ALL || limitTag == entry.tag)) { - stats.insertEntry(entry); - } - - reader.finishLine(); - } - } catch (NullPointerException|NumberFormatException e) { - throw protocolExceptionWithCause("problem parsing idx " + idx, e); - } finally { - IoUtils.closeQuietly(reader); - StrictMode.setThreadPolicy(savedPolicy); - } - - return stats; - } - - public void assertEquals(NetworkStats expected, NetworkStats actual) { - if (expected.size() != actual.size()) { - throw new AssertionError( - "Expected size " + expected.size() + ", actual size " + actual.size()); - } - - NetworkStats.Entry expectedRow = null; - NetworkStats.Entry actualRow = null; - for (int i = 0; i < expected.size(); i++) { - expectedRow = expected.getValues(i, expectedRow); - actualRow = actual.getValues(i, actualRow); - if (!expectedRow.equals(actualRow)) { - throw new AssertionError( - "Expected row " + i + ": " + expectedRow + ", actual row " + actualRow); - } - } - } - - /** - * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming - * format like {@code 0x7fffffff00000000}. - */ - public static int kernelToTag(String string) { - int length = string.length(); - if (length > 10) { - return Long.decode(string.substring(0, length - 8)).intValue(); - } else { - return 0; - } - } - - /** - * Parse statistics from file into given {@link NetworkStats} object. Values - * 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); - - @VisibleForTesting - public static native int nativeReadNetworkStatsDev(NetworkStats stats); - - private static ProtocolException protocolExceptionWithCause(String message, Throwable cause) { - ProtocolException pe = new ProtocolException(message); - pe.initCause(cause); - return pe; - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java deleted file mode 100644 index fdfc893f57cb0..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsObservers.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Copyright (C) 2016 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; - -import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES; - -import android.app.usage.NetworkStatsManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.net.DataUsageRequest; -import android.net.NetworkIdentitySet; -import android.net.NetworkStack; -import android.net.NetworkStats; -import android.net.NetworkStatsAccess; -import android.net.NetworkStatsCollection; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.netstats.IUsageCallback; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Process; -import android.os.RemoteException; -import android.util.ArrayMap; -import android.util.Log; -import android.util.SparseArray; - -import com.android.internal.annotations.VisibleForTesting; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Manages observers of {@link NetworkStats}. Allows observers to be notified when - * data usage has been reported in {@link NetworkStatsService}. An observer can set - * a threshold of how much data it cares about to be notified. - */ -class NetworkStatsObservers { - private static final String TAG = "NetworkStatsObservers"; - private static final boolean LOGV = false; - - private static final int MSG_REGISTER = 1; - private static final int MSG_UNREGISTER = 2; - private static final int MSG_UPDATE_STATS = 3; - - // All access to this map must be done from the handler thread. - // indexed by DataUsageRequest#requestId - private final SparseArray mDataUsageRequests = new SparseArray<>(); - - // Sequence number of DataUsageRequests - private final AtomicInteger mNextDataUsageRequestId = new AtomicInteger(); - - // Lazily instantiated when an observer is registered. - private volatile Handler mHandler; - - /** - * Creates a wrapper that contains the caller context and a normalized request. - * The request should be returned to the caller app, and the wrapper should be sent to this - * object through #addObserver by the service handler. - * - *

It will register the observer asynchronously, so it is safe to call from any thread. - * - * @return the normalized request wrapped within {@link RequestInfo}. - */ - public DataUsageRequest register(Context context, DataUsageRequest inputRequest, - IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) { - DataUsageRequest request = buildRequest(context, inputRequest, callingUid); - RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid, - accessLevel); - - if (LOGV) Log.v(TAG, "Registering observer for " + request); - getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo)); - return request; - } - - /** - * Unregister a data usage observer. - * - *

It will unregister the observer asynchronously, so it is safe to call from any thread. - */ - public void unregister(DataUsageRequest request, int callingUid) { - getHandler().sendMessage(mHandler.obtainMessage(MSG_UNREGISTER, callingUid, 0 /* ignore */, - request)); - } - - /** - * Updates data usage statistics of registered observers and notifies if limits are reached. - * - *

It will update stats asynchronously, so it is safe to call from any thread. - */ - public void updateStats(NetworkStats xtSnapshot, NetworkStats uidSnapshot, - ArrayMap activeIfaces, - ArrayMap activeUidIfaces, - long currentTime) { - StatsContext statsContext = new StatsContext(xtSnapshot, uidSnapshot, activeIfaces, - activeUidIfaces, currentTime); - getHandler().sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATS, statsContext)); - } - - private Handler getHandler() { - if (mHandler == null) { - synchronized (this) { - if (mHandler == null) { - if (LOGV) Log.v(TAG, "Creating handler"); - mHandler = new Handler(getHandlerLooperLocked(), mHandlerCallback); - } - } - } - return mHandler; - } - - @VisibleForTesting - protected Looper getHandlerLooperLocked() { - HandlerThread handlerThread = new HandlerThread(TAG); - handlerThread.start(); - return handlerThread.getLooper(); - } - - private Handler.Callback mHandlerCallback = new Handler.Callback() { - @Override - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_REGISTER: { - handleRegister((RequestInfo) msg.obj); - return true; - } - case MSG_UNREGISTER: { - handleUnregister((DataUsageRequest) msg.obj, msg.arg1 /* callingUid */); - return true; - } - case MSG_UPDATE_STATS: { - handleUpdateStats((StatsContext) msg.obj); - return true; - } - default: { - return false; - } - } - } - }; - - /** - * Adds a {@link RequestInfo} as an observer. - * Should only be called from the handler thread otherwise there will be a race condition - * on mDataUsageRequests. - */ - private void handleRegister(RequestInfo requestInfo) { - mDataUsageRequests.put(requestInfo.mRequest.requestId, requestInfo); - } - - /** - * Removes a {@link DataUsageRequest} if the calling uid is authorized. - * Should only be called from the handler thread otherwise there will be a race condition - * on mDataUsageRequests. - */ - private void handleUnregister(DataUsageRequest request, int callingUid) { - RequestInfo requestInfo; - requestInfo = mDataUsageRequests.get(request.requestId); - if (requestInfo == null) { - if (LOGV) Log.v(TAG, "Trying to unregister unknown request " + request); - return; - } - if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) { - Log.w(TAG, "Caller uid " + callingUid + " is not owner of " + request); - return; - } - - if (LOGV) Log.v(TAG, "Unregistering " + request); - mDataUsageRequests.remove(request.requestId); - requestInfo.unlinkDeathRecipient(); - requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED); - } - - private void handleUpdateStats(StatsContext statsContext) { - if (mDataUsageRequests.size() == 0) { - return; - } - - for (int i = 0; i < mDataUsageRequests.size(); i++) { - RequestInfo requestInfo = mDataUsageRequests.valueAt(i); - requestInfo.updateStats(statsContext); - } - } - - private DataUsageRequest buildRequest(Context context, DataUsageRequest request, - int callingUid) { - // For non-NETWORK_STACK permission uid, cap the minimum threshold to a safe default to - // avoid too many callbacks. - final long thresholdInBytes = (context.checkPermission( - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, Process.myPid(), callingUid) - == PackageManager.PERMISSION_GRANTED ? request.thresholdInBytes - : Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes)); - if (thresholdInBytes > request.thresholdInBytes) { - Log.w(TAG, "Threshold was too low for " + request - + ". Overriding to a safer default of " + thresholdInBytes + " bytes"); - } - return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(), - request.template, thresholdInBytes); - } - - private RequestInfo buildRequestInfo(DataUsageRequest request, IUsageCallback callback, - int callingUid, @NetworkStatsAccess.Level int accessLevel) { - if (accessLevel <= NetworkStatsAccess.Level.USER) { - return new UserUsageRequestInfo(this, request, callback, callingUid, - accessLevel); - } else { - // Safety check in case a new access level is added and we forgot to update this - if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) { - throw new IllegalArgumentException( - "accessLevel " + accessLevel + " is less than DEVICESUMMARY."); - } - return new NetworkUsageRequestInfo(this, request, callback, callingUid, - accessLevel); - } - } - - /** - * Tracks information relevant to a data usage observer. - * It will notice when the calling process dies so we can self-expire. - */ - private abstract static class RequestInfo implements IBinder.DeathRecipient { - private final NetworkStatsObservers mStatsObserver; - protected final DataUsageRequest mRequest; - private final IUsageCallback mCallback; - protected final int mCallingUid; - protected final @NetworkStatsAccess.Level int mAccessLevel; - protected NetworkStatsRecorder mRecorder; - protected NetworkStatsCollection mCollection; - - RequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, - IUsageCallback callback, int callingUid, - @NetworkStatsAccess.Level int accessLevel) { - mStatsObserver = statsObserver; - mRequest = request; - mCallback = callback; - mCallingUid = callingUid; - mAccessLevel = accessLevel; - - try { - mCallback.asBinder().linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - } - } - - @Override - public void binderDied() { - if (LOGV) { - Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mCallback + ")"); - } - mStatsObserver.unregister(mRequest, Process.SYSTEM_UID); - callCallback(NetworkStatsManager.CALLBACK_RELEASED); - } - - @Override - public String toString() { - return "RequestInfo from uid:" + mCallingUid - + " for " + mRequest + " accessLevel:" + mAccessLevel; - } - - private void unlinkDeathRecipient() { - mCallback.asBinder().unlinkToDeath(this, 0); - } - - /** - * Update stats given the samples and interface to identity mappings. - */ - private void updateStats(StatsContext statsContext) { - if (mRecorder == null) { - // First run; establish baseline stats - resetRecorder(); - recordSample(statsContext); - return; - } - recordSample(statsContext); - - if (checkStats()) { - resetRecorder(); - callCallback(NetworkStatsManager.CALLBACK_LIMIT_REACHED); - } - } - - private void callCallback(int callbackType) { - try { - if (LOGV) { - Log.v(TAG, "sending notification " + callbackTypeToName(callbackType) - + " for " + mRequest); - } - switch (callbackType) { - case NetworkStatsManager.CALLBACK_LIMIT_REACHED: - mCallback.onThresholdReached(mRequest); - break; - case NetworkStatsManager.CALLBACK_RELEASED: - mCallback.onCallbackReleased(mRequest); - break; - } - } catch (RemoteException e) { - // May occur naturally in the race of binder death. - Log.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest); - } - } - - private void resetRecorder() { - mRecorder = new NetworkStatsRecorder(); - mCollection = mRecorder.getSinceBoot(); - } - - protected abstract boolean checkStats(); - - protected abstract void recordSample(StatsContext statsContext); - - private String callbackTypeToName(int callbackType) { - switch (callbackType) { - case NetworkStatsManager.CALLBACK_LIMIT_REACHED: - return "LIMIT_REACHED"; - case NetworkStatsManager.CALLBACK_RELEASED: - return "RELEASED"; - default: - return "UNKNOWN"; - } - } - } - - private static class NetworkUsageRequestInfo extends RequestInfo { - NetworkUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, - IUsageCallback callback, int callingUid, - @NetworkStatsAccess.Level int accessLevel) { - super(statsObserver, request, callback, callingUid, accessLevel); - } - - @Override - protected boolean checkStats() { - long bytesSoFar = getTotalBytesForNetwork(mRequest.template); - if (LOGV) { - Log.v(TAG, bytesSoFar + " bytes so far since notification for " - + mRequest.template); - } - if (bytesSoFar > mRequest.thresholdInBytes) { - return true; - } - return false; - } - - @Override - protected void recordSample(StatsContext statsContext) { - // Recorder does not need to be locked in this context since only the handler - // thread will update it. We pass a null VPN array because usage is aggregated by uid - // for this snapshot, so VPN traffic can't be reattributed to responsible apps. - mRecorder.recordSnapshotLocked(statsContext.mXtSnapshot, statsContext.mActiveIfaces, - statsContext.mCurrentTime); - } - - /** - * Reads stats matching the given template. {@link NetworkStatsCollection} will aggregate - * over all buckets, which in this case should be only one since we built it big enough - * that it will outlive the caller. If it doesn't, then there will be multiple buckets. - */ - private long getTotalBytesForNetwork(NetworkTemplate template) { - NetworkStats stats = mCollection.getSummary(template, - Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */, - mAccessLevel, mCallingUid); - return stats.getTotalBytes(); - } - } - - private static class UserUsageRequestInfo extends RequestInfo { - UserUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, - IUsageCallback callback, int callingUid, - @NetworkStatsAccess.Level int accessLevel) { - super(statsObserver, request, callback, callingUid, accessLevel); - } - - @Override - protected boolean checkStats() { - int[] uidsToMonitor = mCollection.getRelevantUids(mAccessLevel, mCallingUid); - - for (int i = 0; i < uidsToMonitor.length; i++) { - long bytesSoFar = getTotalBytesForNetworkUid(mRequest.template, uidsToMonitor[i]); - if (bytesSoFar > mRequest.thresholdInBytes) { - return true; - } - } - return false; - } - - @Override - protected void recordSample(StatsContext statsContext) { - // Recorder does not need to be locked in this context since only the handler - // thread will update it. We pass the VPN info so VPN traffic is reattributed to - // responsible apps. - mRecorder.recordSnapshotLocked(statsContext.mUidSnapshot, statsContext.mActiveUidIfaces, - statsContext.mCurrentTime); - } - - /** - * Reads all stats matching the given template and uid. Ther history will likely only - * contain one bucket per ident since we build it big enough that it will outlive the - * caller lifetime. - */ - private long getTotalBytesForNetworkUid(NetworkTemplate template, int uid) { - try { - NetworkStatsHistory history = mCollection.getHistory(template, null, uid, - NetworkStats.SET_ALL, NetworkStats.TAG_NONE, - NetworkStatsHistory.FIELD_ALL, - Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */, - mAccessLevel, mCallingUid); - return history.getTotalBytes(); - } catch (SecurityException e) { - if (LOGV) { - Log.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid " - + uid); - } - return 0; - } - } - } - - private static class StatsContext { - NetworkStats mXtSnapshot; - NetworkStats mUidSnapshot; - ArrayMap mActiveIfaces; - ArrayMap mActiveUidIfaces; - long mCurrentTime; - - StatsContext(NetworkStats xtSnapshot, NetworkStats uidSnapshot, - ArrayMap activeIfaces, - ArrayMap activeUidIfaces, - long currentTime) { - mXtSnapshot = xtSnapshot; - mUidSnapshot = uidSnapshot; - mActiveIfaces = activeIfaces; - mActiveUidIfaces = activeUidIfaces; - mCurrentTime = currentTime; - } - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java deleted file mode 100644 index f62765d07427d..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsRecorder.java +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (C) 2012 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; - -import static android.net.NetworkStats.TAG_NONE; -import static android.net.TrafficStats.KB_IN_BYTES; -import static android.net.TrafficStats.MB_IN_BYTES; -import static android.text.format.DateUtils.YEAR_IN_MILLIS; - -import android.net.NetworkIdentitySet; -import android.net.NetworkStats; -import android.net.NetworkStats.NonMonotonicObserver; -import android.net.NetworkStatsAccess; -import android.net.NetworkStatsCollection; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.TrafficStats; -import android.os.Binder; -import android.os.DropBoxManager; -import android.service.NetworkStatsRecorderProto; -import android.util.IndentingPrintWriter; -import android.util.Log; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.util.FileRotator; -import com.android.net.module.util.NetworkStatsUtils; - -import libcore.io.IoUtils; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.lang.ref.WeakReference; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; - -/** - * Logic to record deltas between periodic {@link NetworkStats} snapshots into - * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}. - * Keeps pending changes in memory until they pass a specific threshold, in - * bytes. Uses {@link FileRotator} for persistence logic if present. - *

- * Not inherently thread safe. - */ -public class NetworkStatsRecorder { - private static final String TAG = "NetworkStatsRecorder"; - private static final boolean LOGD = false; - private static final boolean LOGV = false; - - private static final String TAG_NETSTATS_DUMP = "netstats_dump"; - - /** Dump before deleting in {@link #recoverFromWtf()}. */ - private static final boolean DUMP_BEFORE_DELETE = true; - - private final FileRotator mRotator; - private final NonMonotonicObserver mObserver; - private final DropBoxManager mDropBox; - private final String mCookie; - - private final long mBucketDuration; - private final boolean mOnlyTags; - - private long mPersistThresholdBytes = 2 * MB_IN_BYTES; - private NetworkStats mLastSnapshot; - - private final NetworkStatsCollection mPending; - private final NetworkStatsCollection mSinceBoot; - - private final CombiningRewriter mPendingRewriter; - - private WeakReference mComplete; - - /** - * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}. - */ - public NetworkStatsRecorder() { - mRotator = null; - mObserver = null; - mDropBox = null; - mCookie = null; - - // set the bucket big enough to have all data in one bucket, but allow some - // slack to avoid overflow - mBucketDuration = YEAR_IN_MILLIS; - mOnlyTags = false; - - mPending = null; - mSinceBoot = new NetworkStatsCollection(mBucketDuration); - - mPendingRewriter = null; - } - - /** - * Persisted recorder. - */ - public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver observer, - DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) { - mRotator = Objects.requireNonNull(rotator, "missing FileRotator"); - mObserver = Objects.requireNonNull(observer, "missing NonMonotonicObserver"); - mDropBox = Objects.requireNonNull(dropBox, "missing DropBoxManager"); - mCookie = cookie; - - mBucketDuration = bucketDuration; - mOnlyTags = onlyTags; - - mPending = new NetworkStatsCollection(bucketDuration); - mSinceBoot = new NetworkStatsCollection(bucketDuration); - - mPendingRewriter = new CombiningRewriter(mPending); - } - - public void setPersistThreshold(long thresholdBytes) { - if (LOGV) Log.v(TAG, "setPersistThreshold() with " + thresholdBytes); - mPersistThresholdBytes = NetworkStatsUtils.constrain( - thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES); - } - - public void resetLocked() { - mLastSnapshot = null; - if (mPending != null) { - mPending.reset(); - } - if (mSinceBoot != null) { - mSinceBoot.reset(); - } - if (mComplete != null) { - mComplete.clear(); - } - } - - public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) { - return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE, - NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotal(null); - } - - public NetworkStatsCollection getSinceBoot() { - return mSinceBoot; - } - - /** - * Load complete history represented by {@link FileRotator}. Caches - * internally as a {@link WeakReference}, and updated with future - * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long - * as reference is valid. - */ - public NetworkStatsCollection getOrLoadCompleteLocked() { - Objects.requireNonNull(mRotator, "missing FileRotator"); - NetworkStatsCollection res = mComplete != null ? mComplete.get() : null; - if (res == null) { - res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE); - mComplete = new WeakReference(res); - } - return res; - } - - public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) { - Objects.requireNonNull(mRotator, "missing FileRotator"); - NetworkStatsCollection res = mComplete != null ? mComplete.get() : null; - if (res == null) { - res = loadLocked(start, end); - } - return res; - } - - private NetworkStatsCollection loadLocked(long start, long end) { - if (LOGD) Log.d(TAG, "loadLocked() reading from disk for " + mCookie); - final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration); - try { - mRotator.readMatching(res, start, end); - res.recordCollection(mPending); - } catch (IOException e) { - Log.wtf(TAG, "problem completely reading network stats", e); - recoverFromWtf(); - } catch (OutOfMemoryError e) { - Log.wtf(TAG, "problem completely reading network stats", e); - recoverFromWtf(); - } - return res; - } - - /** - * Record any delta that occurred since last {@link NetworkStats} snapshot, using the given - * {@link Map} to identify network interfaces. First snapshot is considered bootstrap, and is - * not counted as delta. - */ - public void recordSnapshotLocked(NetworkStats snapshot, - Map ifaceIdent, long currentTimeMillis) { - final HashSet unknownIfaces = new HashSet<>(); - - // skip recording when snapshot missing - if (snapshot == null) return; - - // assume first snapshot is bootstrap and don't record - if (mLastSnapshot == null) { - mLastSnapshot = snapshot; - return; - } - - final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; - - final NetworkStats delta = NetworkStats.subtract( - snapshot, mLastSnapshot, mObserver, mCookie); - final long end = currentTimeMillis; - final long start = end - delta.getElapsedRealtime(); - - NetworkStats.Entry entry = null; - for (int i = 0; i < delta.size(); i++) { - entry = delta.getValues(i, entry); - - // As a last-ditch check, report any negative values and - // clamp them so recording below doesn't croak. - if (entry.isNegative()) { - if (mObserver != null) { - mObserver.foundNonMonotonic(delta, i, mCookie); - } - entry.rxBytes = Math.max(entry.rxBytes, 0); - entry.rxPackets = Math.max(entry.rxPackets, 0); - entry.txBytes = Math.max(entry.txBytes, 0); - entry.txPackets = Math.max(entry.txPackets, 0); - entry.operations = Math.max(entry.operations, 0); - } - - final NetworkIdentitySet ident = ifaceIdent.get(entry.iface); - if (ident == null) { - unknownIfaces.add(entry.iface); - continue; - } - - // skip when no delta occurred - if (entry.isEmpty()) continue; - - // only record tag data when requested - if ((entry.tag == TAG_NONE) != mOnlyTags) { - if (mPending != null) { - mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); - } - - // also record against boot stats when present - if (mSinceBoot != null) { - mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); - } - - // also record against complete dataset when present - if (complete != null) { - complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); - } - } - } - - mLastSnapshot = snapshot; - - if (LOGV && unknownIfaces.size() > 0) { - Log.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats"); - } - } - - /** - * Consider persisting any pending deltas, if they are beyond - * {@link #mPersistThresholdBytes}. - */ - public void maybePersistLocked(long currentTimeMillis) { - Objects.requireNonNull(mRotator, "missing FileRotator"); - final long pendingBytes = mPending.getTotalBytes(); - if (pendingBytes >= mPersistThresholdBytes) { - forcePersistLocked(currentTimeMillis); - } else { - mRotator.maybeRotate(currentTimeMillis); - } - } - - /** - * Force persisting any pending deltas. - */ - public void forcePersistLocked(long currentTimeMillis) { - Objects.requireNonNull(mRotator, "missing FileRotator"); - if (mPending.isDirty()) { - if (LOGD) Log.d(TAG, "forcePersistLocked() writing for " + mCookie); - try { - mRotator.rewriteActive(mPendingRewriter, currentTimeMillis); - mRotator.maybeRotate(currentTimeMillis); - mPending.reset(); - } catch (IOException e) { - Log.wtf(TAG, "problem persisting pending stats", e); - recoverFromWtf(); - } catch (OutOfMemoryError e) { - Log.wtf(TAG, "problem persisting pending stats", e); - recoverFromWtf(); - } - } - } - - /** - * Remove the given UID from all {@link FileRotator} history, migrating it - * to {@link TrafficStats#UID_REMOVED}. - */ - public void removeUidsLocked(int[] uids) { - if (mRotator != null) { - try { - // Rewrite all persisted data to migrate UID stats - mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids)); - } catch (IOException e) { - Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); - recoverFromWtf(); - } catch (OutOfMemoryError e) { - Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); - recoverFromWtf(); - } - } - - // Remove any pending stats - if (mPending != null) { - mPending.removeUids(uids); - } - if (mSinceBoot != null) { - mSinceBoot.removeUids(uids); - } - - // Clear UID from current stats snapshot - if (mLastSnapshot != null) { - mLastSnapshot.removeUids(uids); - } - - final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; - if (complete != null) { - complete.removeUids(uids); - } - } - - /** - * Rewriter that will combine current {@link NetworkStatsCollection} values - * with anything read from disk, and write combined set to disk. Clears the - * original {@link NetworkStatsCollection} when finished writing. - */ - private static class CombiningRewriter implements FileRotator.Rewriter { - private final NetworkStatsCollection mCollection; - - public CombiningRewriter(NetworkStatsCollection collection) { - mCollection = Objects.requireNonNull(collection, "missing NetworkStatsCollection"); - } - - @Override - public void reset() { - // ignored - } - - @Override - public void read(InputStream in) throws IOException { - mCollection.read(in); - } - - @Override - public boolean shouldWrite() { - return true; - } - - @Override - public void write(OutputStream out) throws IOException { - mCollection.write(out); - mCollection.reset(); - } - } - - /** - * Rewriter that will remove any {@link NetworkStatsHistory} attributed to - * the requested UID, only writing data back when modified. - */ - public static class RemoveUidRewriter implements FileRotator.Rewriter { - private final NetworkStatsCollection mTemp; - private final int[] mUids; - - public RemoveUidRewriter(long bucketDuration, int[] uids) { - mTemp = new NetworkStatsCollection(bucketDuration); - mUids = uids; - } - - @Override - public void reset() { - mTemp.reset(); - } - - @Override - public void read(InputStream in) throws IOException { - mTemp.read(in); - mTemp.clearDirty(); - mTemp.removeUids(mUids); - } - - @Override - public boolean shouldWrite() { - return mTemp.isDirty(); - } - - @Override - public void write(OutputStream out) throws IOException { - mTemp.write(out); - } - } - - public void importLegacyNetworkLocked(File file) throws IOException { - Objects.requireNonNull(mRotator, "missing FileRotator"); - - // legacy file still exists; start empty to avoid double importing - mRotator.deleteAll(); - - final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration); - collection.readLegacyNetwork(file); - - final long startMillis = collection.getStartMillis(); - final long endMillis = collection.getEndMillis(); - - if (!collection.isEmpty()) { - // process legacy data, creating active file at starting time, then - // using end time to possibly trigger rotation. - mRotator.rewriteActive(new CombiningRewriter(collection), startMillis); - mRotator.maybeRotate(endMillis); - } - } - - public void importLegacyUidLocked(File file) throws IOException { - Objects.requireNonNull(mRotator, "missing FileRotator"); - - // legacy file still exists; start empty to avoid double importing - mRotator.deleteAll(); - - final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration); - collection.readLegacyUid(file, mOnlyTags); - - final long startMillis = collection.getStartMillis(); - final long endMillis = collection.getEndMillis(); - - if (!collection.isEmpty()) { - // process legacy data, creating active file at starting time, then - // using end time to possibly trigger rotation. - mRotator.rewriteActive(new CombiningRewriter(collection), startMillis); - mRotator.maybeRotate(endMillis); - } - } - - public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) { - if (mPending != null) { - pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes()); - } - if (fullHistory) { - pw.println("Complete history:"); - getOrLoadCompleteLocked().dump(pw); - } else { - pw.println("History since boot:"); - mSinceBoot.dump(pw); - } - } - - public void dumpDebugLocked(ProtoOutputStream proto, long tag) { - final long start = proto.start(tag); - if (mPending != null) { - proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, - mPending.getTotalBytes()); - } - getOrLoadCompleteLocked().dumpDebug(proto, - NetworkStatsRecorderProto.COMPLETE_HISTORY); - proto.end(start); - } - - public void dumpCheckin(PrintWriter pw, long start, long end) { - // Only load and dump stats from the requested window - getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end); - } - - /** - * Recover from {@link FileRotator} failure by dumping state to - * {@link DropBoxManager} and deleting contents. - */ - private void recoverFromWtf() { - if (DUMP_BEFORE_DELETE) { - final ByteArrayOutputStream os = new ByteArrayOutputStream(); - try { - mRotator.dumpAll(os); - } catch (IOException e) { - // ignore partial contents - os.reset(); - } finally { - IoUtils.closeQuietly(os); - } - mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0); - } - - mRotator.deleteAll(); - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java deleted file mode 100644 index e3794e441a237..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java +++ /dev/null @@ -1,2528 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import static android.Manifest.permission.NETWORK_STATS_PROVIDER; -import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; -import static android.Manifest.permission.UPDATE_DEVICE_STATS; -import static android.app.usage.NetworkStatsManager.PREFIX_DEV; -import static android.content.Intent.ACTION_SHUTDOWN; -import static android.content.Intent.ACTION_UID_REMOVED; -import static android.content.Intent.ACTION_USER_REMOVED; -import static android.content.Intent.EXTRA_UID; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; -import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; -import static android.net.NetworkStats.IFACE_ALL; -import static android.net.NetworkStats.IFACE_VT; -import static android.net.NetworkStats.INTERFACES_ALL; -import static android.net.NetworkStats.METERED_ALL; -import static android.net.NetworkStats.ROAMING_ALL; -import static android.net.NetworkStats.SET_ALL; -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.SET_FOREGROUND; -import static android.net.NetworkStats.STATS_PER_IFACE; -import static android.net.NetworkStats.STATS_PER_UID; -import static android.net.NetworkStats.TAG_ALL; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkStatsHistory.FIELD_ALL; -import static android.net.NetworkTemplate.buildTemplateMobileWildcard; -import static android.net.NetworkTemplate.buildTemplateWifiWildcard; -import static android.net.TrafficStats.KB_IN_BYTES; -import static android.net.TrafficStats.MB_IN_BYTES; -import static android.net.TrafficStats.UID_TETHERING; -import static android.net.TrafficStats.UNSUPPORTED; -import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID; -import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG; -import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT; -import static android.os.Trace.TRACE_TAG_NETWORK; -import static android.system.OsConstants.ENOENT; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static android.text.format.DateUtils.DAY_IN_MILLIS; -import static android.text.format.DateUtils.HOUR_IN_MILLIS; -import static android.text.format.DateUtils.MINUTE_IN_MILLIS; -import static android.text.format.DateUtils.SECOND_IN_MILLIS; - -import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport; -import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.TargetApi; -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.usage.NetworkStatsManager; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.database.ContentObserver; -import android.net.DataUsageRequest; -import android.net.INetd; -import android.net.INetworkStatsService; -import android.net.INetworkStatsSession; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkIdentity; -import android.net.NetworkIdentitySet; -import android.net.NetworkPolicyManager; -import android.net.NetworkSpecifier; -import android.net.NetworkStack; -import android.net.NetworkStateSnapshot; -import android.net.NetworkStats; -import android.net.NetworkStats.NonMonotonicObserver; -import android.net.NetworkStatsAccess; -import android.net.NetworkStatsCollection; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.TelephonyNetworkSpecifier; -import android.net.TetherStatsParcel; -import android.net.TetheringManager; -import android.net.TrafficStats; -import android.net.UnderlyingNetworkInfo; -import android.net.Uri; -import android.net.netstats.IUsageCallback; -import android.net.netstats.provider.INetworkStatsProvider; -import android.net.netstats.provider.INetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProvider; -import android.os.Binder; -import android.os.Build; -import android.os.DropBoxManager; -import android.os.Environment; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.os.SystemClock; -import android.os.Trace; -import android.os.UserHandle; -import android.provider.Settings; -import android.provider.Settings.Global; -import android.service.NetworkInterfaceProto; -import android.service.NetworkStatsServiceDumpProto; -import android.system.ErrnoException; -import android.telephony.PhoneStateListener; -import android.telephony.SubscriptionPlan; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.EventLog; -import android.util.IndentingPrintWriter; -import android.util.Log; -import android.util.SparseIntArray; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.FileRotator; -import com.android.net.module.util.BaseNetdUnsolicitedEventListener; -import com.android.net.module.util.BestClock; -import com.android.net.module.util.BinderUtils; -import com.android.net.module.util.BpfMap; -import com.android.net.module.util.CollectionUtils; -import com.android.net.module.util.IBpfMap; -import com.android.net.module.util.LocationPermissionChecker; -import com.android.net.module.util.NetworkStatsUtils; -import com.android.net.module.util.PermissionUtils; -import com.android.net.module.util.Struct.U32; -import com.android.net.module.util.Struct.U8; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.time.Clock; -import java.time.ZoneOffset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; - -/** - * Collect and persist detailed network statistics, and provide this data to - * other system services. - */ -@TargetApi(Build.VERSION_CODES.TIRAMISU) -public class NetworkStatsService extends INetworkStatsService.Stub { - static { - System.loadLibrary("service-connectivity"); - } - - static final String TAG = "NetworkStats"; - static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); - static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); - - // Perform polling and persist all (FLAG_PERSIST_ALL). - private static final int MSG_PERFORM_POLL = 1; - // Perform polling, persist network, and register the global alert again. - private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; - private static final int MSG_NOTIFY_NETWORK_STATUS = 3; - // 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. - * This avoids firing the global alert too often on devices with high transfer speeds and - * high quota. - */ - private static final int DEFAULT_PERFORM_POLL_DELAY_MS = 1000; - - private static final String TAG_NETSTATS_ERROR = "netstats_error"; - - /** - * EventLog tags used when logging into the event log. Note the values must be sync with - * frameworks/base/services/core/java/com/android/server/EventLogTags.logtags to get correct - * name translation. - */ - private static final int LOG_TAG_NETSTATS_MOBILE_SAMPLE = 51100; - private static final int LOG_TAG_NETSTATS_WIFI_SAMPLE = 51101; - - // TODO: Replace the hardcoded string and move it into ConnectivitySettingsManager. - private static final String NETSTATS_COMBINE_SUBTYPE_ENABLED = - "netstats_combine_subtype_enabled"; - - // This is current path but may be changed soon. - private static final String UID_COUNTERSET_MAP_PATH = - "/sys/fs/bpf/map_netd_uid_counterset_map"; - private static final String COOKIE_TAG_MAP_PATH = - "/sys/fs/bpf/map_netd_cookie_tag_map"; - private static final String APP_UID_STATS_MAP_PATH = - "/sys/fs/bpf/map_netd_app_uid_stats_map"; - private static final String STATS_MAP_A_PATH = - "/sys/fs/bpf/map_netd_stats_map_A"; - private static final String STATS_MAP_B_PATH = - "/sys/fs/bpf/map_netd_stats_map_B"; - - private final Context mContext; - private final NetworkStatsFactory mStatsFactory; - private final AlarmManager mAlarmManager; - private final Clock mClock; - private final NetworkStatsSettings mSettings; - private final NetworkStatsObservers mStatsObservers; - - private final File mSystemDir; - private final File mBaseDir; - - private final PowerManager.WakeLock mWakeLock; - - private final ContentObserver mContentObserver; - private final ContentResolver mContentResolver; - - protected INetd mNetd; - private final AlertObserver mAlertObserver = new AlertObserver(); - - @VisibleForTesting - public static final String ACTION_NETWORK_STATS_POLL = - "com.android.server.action.NETWORK_STATS_POLL"; - public static final String ACTION_NETWORK_STATS_UPDATED = - "com.android.server.action.NETWORK_STATS_UPDATED"; - - private PendingIntent mPollIntent; - - /** - * Settings that can be changed externally. - */ - public interface NetworkStatsSettings { - long getPollInterval(); - long getPollDelay(); - boolean getSampleEnabled(); - boolean getAugmentEnabled(); - /** - * When enabled, all mobile data is reported under {@link NetworkTemplate#NETWORK_TYPE_ALL}. - * When disabled, mobile data is broken down by a granular ratType representative of the - * actual ratType. {@see android.app.usage.NetworkStatsManager#getCollapsedRatType}. - * Enabling this decreases the level of detail but saves performance, disk space and - * amount of data logged. - */ - boolean getCombineSubtypeEnabled(); - - class Config { - public final long bucketDuration; - public final long rotateAgeMillis; - public final long deleteAgeMillis; - - public Config(long bucketDuration, long rotateAgeMillis, long deleteAgeMillis) { - this.bucketDuration = bucketDuration; - this.rotateAgeMillis = rotateAgeMillis; - this.deleteAgeMillis = deleteAgeMillis; - } - } - - Config getDevConfig(); - Config getXtConfig(); - Config getUidConfig(); - Config getUidTagConfig(); - - long getGlobalAlertBytes(long def); - long getDevPersistBytes(long def); - long getXtPersistBytes(long def); - long getUidPersistBytes(long def); - long getUidTagPersistBytes(long def); - } - - private final Object mStatsLock = new Object(); - - /** Set of currently active ifaces. */ - @GuardedBy("mStatsLock") - private final ArrayMap mActiveIfaces = new ArrayMap<>(); - - /** Set of currently active ifaces for UID stats. */ - @GuardedBy("mStatsLock") - private final ArrayMap mActiveUidIfaces = new ArrayMap<>(); - - /** Current default active iface. */ - @GuardedBy("mStatsLock") - private String mActiveIface; - - /** Set of any ifaces associated with mobile networks since boot. */ - private volatile String[] mMobileIfaces = new String[0]; - - /** Set of any ifaces associated with wifi networks since boot. */ - private volatile String[] mWifiIfaces = new String[0]; - - /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */ - @GuardedBy("mStatsLock") - private Network[] mDefaultNetworks = new Network[0]; - - /** Last states of all networks sent from ConnectivityService. */ - @GuardedBy("mStatsLock") - @Nullable - private NetworkStateSnapshot[] mLastNetworkStateSnapshots = null; - - private final DropBoxNonMonotonicObserver mNonMonotonicObserver = - new DropBoxNonMonotonicObserver(); - - private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100; - private final CopyOnWriteArrayList mStatsProviderCbList = - new CopyOnWriteArrayList<>(); - /** Semaphore used to wait for stats provider to respond to request stats update. */ - private final Semaphore mStatsProviderSem = new Semaphore(0, true); - - @GuardedBy("mStatsLock") - private NetworkStatsRecorder mDevRecorder; - @GuardedBy("mStatsLock") - private NetworkStatsRecorder mXtRecorder; - @GuardedBy("mStatsLock") - private NetworkStatsRecorder mUidRecorder; - @GuardedBy("mStatsLock") - private NetworkStatsRecorder mUidTagRecorder; - - /** Cached {@link #mXtRecorder} stats. */ - @GuardedBy("mStatsLock") - private NetworkStatsCollection mXtStatsCached; - - /** - * Current counter sets for each UID. - * TODO: maybe remove mActiveUidCounterSet and read UidCouneterSet value from mUidCounterSetMap - * directly ? But if mActiveUidCounterSet would be accessed very frequently, maybe keep - * mActiveUidCounterSet to avoid accessing kernel too frequently. - */ - private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); - private final IBpfMap mUidCounterSetMap; - private final IBpfMap mCookieTagMap; - private final IBpfMap mStatsMapA; - private final IBpfMap mStatsMapB; - private final IBpfMap mAppUidStatsMap; - - /** Data layer operation counters for splicing into other structures. */ - private NetworkStats mUidOperations = new NetworkStats(0L, 10); - - @NonNull - private final Handler mHandler; - - private volatile boolean mSystemReady; - private long mPersistThreshold = 2 * MB_IN_BYTES; - private long mGlobalAlertBytes; - - private static final long POLL_RATE_LIMIT_MS = 15_000; - - private long mLastStatsSessionPoll; - - /** Map from UID to number of opened sessions */ - @GuardedBy("mOpenSessionCallsPerUid") - private final SparseIntArray mOpenSessionCallsPerUid = new SparseIntArray(); - - private final static int DUMP_STATS_SESSION_COUNT = 20; - - @NonNull - private final Dependencies mDeps; - - @NonNull - private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor; - - @NonNull - private final LocationPermissionChecker mLocationPermissionChecker; - - @NonNull - private final BpfInterfaceMapUpdater mInterfaceMapUpdater; - - private static @NonNull File getDefaultSystemDir() { - return new File(Environment.getDataDirectory(), "system"); - } - - private static @NonNull File getDefaultBaseDir() { - File baseDir = new File(getDefaultSystemDir(), "netstats"); - baseDir.mkdirs(); - return baseDir; - } - - private static @NonNull Clock getDefaultClock() { - return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(), - Clock.systemUTC()); - } - - private final class NetworkStatsHandler extends Handler { - NetworkStatsHandler(@NonNull Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_PERFORM_POLL: { - performPoll(FLAG_PERSIST_ALL); - break; - } - case MSG_NOTIFY_NETWORK_STATUS: { - // If no cached states, ignore. - if (mLastNetworkStateSnapshots == null) break; - // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing. - handleNotifyNetworkStatus( - mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); - break; - } - case MSG_PERFORM_POLL_REGISTER_ALERT: { - performPoll(FLAG_PERSIST_NETWORK); - registerGlobalAlert(); - break; - } - case MSG_BROADCAST_NETWORK_STATS_UPDATED: { - final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); - updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL, - READ_NETWORK_USAGE_HISTORY); - break; - } - } - } - } - - /** Creates a new NetworkStatsService */ - public static NetworkStatsService create(Context context) { - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - PowerManager.WakeLock wakeLock = - powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - final INetd netd = INetd.Stub.asInterface( - (IBinder) context.getSystemService(Context.NETD_SERVICE)); - final NetworkStatsService service = new NetworkStatsService(context, - INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)), - alarmManager, wakeLock, getDefaultClock(), - new DefaultNetworkStatsSettings(), new NetworkStatsFactory(context), - new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), - new Dependencies()); - - return service; - } - - // This must not be called outside of tests, even within the same package, as this constructor - // does not register the local service. Use the create() helper above. - @VisibleForTesting - NetworkStatsService(Context context, INetd netd, AlarmManager alarmManager, - PowerManager.WakeLock wakeLock, Clock clock, NetworkStatsSettings settings, - NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, - File baseDir, @NonNull Dependencies deps) { - mContext = Objects.requireNonNull(context, "missing Context"); - mNetd = Objects.requireNonNull(netd, "missing Netd"); - mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager"); - mClock = Objects.requireNonNull(clock, "missing Clock"); - mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings"); - mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock"); - mStatsFactory = Objects.requireNonNull(factory, "missing factory"); - mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers"); - mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir"); - mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir"); - mDeps = Objects.requireNonNull(deps, "missing Dependencies"); - - final HandlerThread handlerThread = mDeps.makeHandlerThread(); - handlerThread.start(); - mHandler = new NetworkStatsHandler(handlerThread.getLooper()); - mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, - (command) -> mHandler.post(command) , this); - mContentResolver = mContext.getContentResolver(); - mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, - mNetworkStatsSubscriptionsMonitor); - mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext); - mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler); - mInterfaceMapUpdater.start(); - mUidCounterSetMap = mDeps.getUidCounterSetMap(); - mCookieTagMap = mDeps.getCookieTagMap(); - mStatsMapA = mDeps.getStatsMapA(); - mStatsMapB = mDeps.getStatsMapB(); - mAppUidStatsMap = mDeps.getAppUidStatsMap(); - } - - /** - * Dependencies of NetworkStatsService, for injection in tests. - */ - // TODO: Move more stuff into dependencies object. - @VisibleForTesting - public static class Dependencies { - /** - * Create a HandlerThread to use in NetworkStatsService. - */ - @NonNull - public HandlerThread makeHandlerThread() { - return new HandlerThread(TAG); - } - - /** - * Create a {@link NetworkStatsSubscriptionsMonitor}, can be used to monitor RAT change - * event in NetworkStatsService. - */ - @NonNull - public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(@NonNull Context context, - @NonNull Executor executor, @NonNull NetworkStatsService service) { - // TODO: Update RatType passively in NSS, instead of querying into the monitor - // when notifyNetworkStatus. - return new NetworkStatsSubscriptionsMonitor(context, executor, - (subscriberId, type) -> service.handleOnCollapsedRatTypeChanged()); - } - - /** - * Create a ContentObserver instance which is used to observe settings changes, - * and dispatch onChange events on handler thread. - */ - public @NonNull ContentObserver makeContentObserver(@NonNull Handler handler, - @NonNull NetworkStatsSettings settings, - @NonNull NetworkStatsSubscriptionsMonitor monitor) { - return new ContentObserver(handler) { - @Override - public void onChange(boolean selfChange, @NonNull Uri uri) { - if (!settings.getCombineSubtypeEnabled()) { - monitor.start(); - } else { - monitor.stop(); - } - } - }; - } - - /** - * @see LocationPermissionChecker - */ - public LocationPermissionChecker makeLocationPermissionChecker(final Context context) { - return new LocationPermissionChecker(context); - } - - /** Create BpfInterfaceMapUpdater to update bpf interface map. */ - @NonNull - public BpfInterfaceMapUpdater makeBpfInterfaceMapUpdater( - @NonNull Context ctx, @NonNull Handler handler) { - return new BpfInterfaceMapUpdater(ctx, handler); - } - - /** Get counter sets map for each UID. */ - public IBpfMap getUidCounterSetMap() { - try { - return new BpfMap(UID_COUNTERSET_MAP_PATH, BpfMap.BPF_F_RDWR, - U32.class, U8.class); - } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot open uid counter set map: " + e); - return null; - } - } - - /** Gets the cookie tag map */ - public IBpfMap getCookieTagMap() { - try { - return new BpfMap(COOKIE_TAG_MAP_PATH, - BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class); - } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot open cookie tag map: " + e); - return null; - } - } - - /** Gets stats map A */ - public IBpfMap getStatsMapA() { - try { - return new BpfMap(STATS_MAP_A_PATH, - BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class); - } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot open stats map A: " + e); - return null; - } - } - - /** Gets stats map B */ - public IBpfMap getStatsMapB() { - try { - return new BpfMap(STATS_MAP_B_PATH, - BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class); - } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot open stats map B: " + e); - return null; - } - } - - /** Gets the uid stats map */ - public IBpfMap getAppUidStatsMap() { - try { - return new BpfMap(APP_UID_STATS_MAP_PATH, - BpfMap.BPF_F_RDWR, UidStatsMapKey.class, StatsMapValue.class); - } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot open app uid stats map: " + e); - return null; - } - } - } - - /** - * Observer that watches for {@link INetdUnsolicitedEventListener} alerts. - */ - @VisibleForTesting - public class AlertObserver extends BaseNetdUnsolicitedEventListener { - @Override - public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) { - PermissionUtils.enforceNetworkStackPermission(mContext); - - if (LIMIT_GLOBAL_ALERT.equals(alertName)) { - // kick off background poll to collect network stats unless there is already - // such a call pending; UID stats are handled during normal polling interval. - if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) { - mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT, - mSettings.getPollDelay()); - } - } - } - } - - public void systemReady() { - synchronized (mStatsLock) { - mSystemReady = true; - - // create data recorders along with historical rotators - mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false); - mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false); - mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false); - mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true); - - updatePersistThresholdsLocked(); - - // upgrade any legacy stats, migrating them to rotated files - maybeUpgradeLegacyStatsLocked(); - - // read historical network stats from disk, since policy service - // might need them right away. - mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked(); - - // bootstrap initial stats to prevent double-counting later - bootstrapStatsLocked(); - } - - // watch for tethering changes - final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); - tetheringManager.registerTetheringEventCallback( - (command) -> mHandler.post(command), mTetherListener); - - // listen for periodic polling events - final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); - mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler); - - // listen for uid removal to clean stats - final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED); - mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler); - - // listen for user changes to clean stats - final IntentFilter userFilter = new IntentFilter(ACTION_USER_REMOVED); - mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); - - // persist stats during clean shutdown - final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN); - mContext.registerReceiver(mShutdownReceiver, shutdownFilter); - - try { - mNetd.registerUnsolicitedEventListener(mAlertObserver); - } catch (RemoteException | ServiceSpecificException e) { - Log.wtf(TAG, "Error registering event listener :", e); - } - - // schedule periodic pall alarm based on {@link NetworkStatsSettings#getPollInterval()}. - final PendingIntent pollIntent = - PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), - PendingIntent.FLAG_IMMUTABLE); - - final long currentRealtime = SystemClock.elapsedRealtime(); - mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, - mSettings.getPollInterval(), pollIntent); - - mContentResolver.registerContentObserver(Settings.Global - .getUriFor(NETSTATS_COMBINE_SUBTYPE_ENABLED), - false /* notifyForDescendants */, mContentObserver); - - // Post a runnable on handler thread to call onChange(). It's for getting current value of - // NETSTATS_COMBINE_SUBTYPE_ENABLED to decide start or stop monitoring RAT type changes. - mHandler.post(() -> mContentObserver.onChange(false, Settings.Global - .getUriFor(NETSTATS_COMBINE_SUBTYPE_ENABLED))); - - registerGlobalAlert(); - } - - private NetworkStatsRecorder buildRecorder( - String prefix, NetworkStatsSettings.Config config, boolean includeTags) { - final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService( - Context.DROPBOX_SERVICE); - return new NetworkStatsRecorder(new FileRotator( - mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis), - mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags); - } - - @GuardedBy("mStatsLock") - private void shutdownLocked() { - final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); - tetheringManager.unregisterTetheringEventCallback(mTetherListener); - mContext.unregisterReceiver(mPollReceiver); - mContext.unregisterReceiver(mRemovedReceiver); - mContext.unregisterReceiver(mUserReceiver); - mContext.unregisterReceiver(mShutdownReceiver); - - if (!mSettings.getCombineSubtypeEnabled()) { - mNetworkStatsSubscriptionsMonitor.stop(); - } - - mContentResolver.unregisterContentObserver(mContentObserver); - - final long currentTime = mClock.millis(); - - // persist any pending stats - mDevRecorder.forcePersistLocked(currentTime); - mXtRecorder.forcePersistLocked(currentTime); - mUidRecorder.forcePersistLocked(currentTime); - mUidTagRecorder.forcePersistLocked(currentTime); - - mSystemReady = false; - } - - @GuardedBy("mStatsLock") - private void maybeUpgradeLegacyStatsLocked() { - File file; - try { - file = new File(mSystemDir, "netstats.bin"); - if (file.exists()) { - mDevRecorder.importLegacyNetworkLocked(file); - file.delete(); - } - - file = new File(mSystemDir, "netstats_xt.bin"); - if (file.exists()) { - file.delete(); - } - - file = new File(mSystemDir, "netstats_uid.bin"); - if (file.exists()) { - mUidRecorder.importLegacyUidLocked(file); - mUidTagRecorder.importLegacyUidLocked(file); - file.delete(); - } - } catch (IOException e) { - Log.wtf(TAG, "problem during legacy upgrade", e); - } catch (OutOfMemoryError e) { - Log.wtf(TAG, "problem during legacy upgrade", e); - } - } - - /** - * Register for a global alert that is delivered through {@link AlertObserver} - * or {@link NetworkStatsProviderCallback#onAlertReached()} once a threshold amount of data has - * been transferred. - */ - private void registerGlobalAlert() { - try { - mNetd.bandwidthSetGlobalAlert(mGlobalAlertBytes); - } catch (IllegalStateException e) { - Log.w(TAG, "problem registering for global alert: " + e); - } catch (RemoteException e) { - // ignored; service lives in system_server - } - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetAlert(mGlobalAlertBytes)); - } - - @Override - public INetworkStatsSession openSession() { - return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null); - } - - @Override - public INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage) { - return openSessionInternal(flags, callingPackage); - } - - private boolean isRateLimitedForPoll(int callingUid) { - if (callingUid == android.os.Process.SYSTEM_UID) { - return false; - } - - final long lastCallTime; - final long now = SystemClock.elapsedRealtime(); - synchronized (mOpenSessionCallsPerUid) { - int calls = mOpenSessionCallsPerUid.get(callingUid, 0); - mOpenSessionCallsPerUid.put(callingUid, calls + 1); - lastCallTime = mLastStatsSessionPoll; - mLastStatsSessionPoll = now; - } - - return now - lastCallTime < POLL_RATE_LIMIT_MS; - } - - private int restrictFlagsForCaller(int flags) { - // All non-privileged callers are not allowed to turn off POLL_ON_OPEN. - final boolean isPrivileged = PermissionUtils.checkAnyPermissionOf(mContext, - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK); - if (!isPrivileged) { - flags |= NetworkStatsManager.FLAG_POLL_ON_OPEN; - } - // Non-system uids are rate limited for POLL_ON_OPEN. - final int callingUid = Binder.getCallingUid(); - flags = isRateLimitedForPoll(callingUid) - ? flags & (~NetworkStatsManager.FLAG_POLL_ON_OPEN) - : flags; - return flags; - } - - private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) { - final int restrictedFlags = restrictFlagsForCaller(flags); - if ((restrictedFlags & (NetworkStatsManager.FLAG_POLL_ON_OPEN - | NetworkStatsManager.FLAG_POLL_FORCE)) != 0) { - final long ident = Binder.clearCallingIdentity(); - try { - performPoll(FLAG_PERSIST_ALL); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - // return an IBinder which holds strong references to any loaded stats - // for its lifetime; when caller closes only weak references remain. - - return new INetworkStatsSession.Stub() { - private final int mCallingUid = Binder.getCallingUid(); - private final String mCallingPackage = callingPackage; - private final @NetworkStatsAccess.Level int mAccessLevel = checkAccessLevel( - callingPackage); - - private NetworkStatsCollection mUidComplete; - private NetworkStatsCollection mUidTagComplete; - - private NetworkStatsCollection getUidComplete() { - synchronized (mStatsLock) { - if (mUidComplete == null) { - mUidComplete = mUidRecorder.getOrLoadCompleteLocked(); - } - return mUidComplete; - } - } - - private NetworkStatsCollection getUidTagComplete() { - synchronized (mStatsLock) { - if (mUidTagComplete == null) { - mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked(); - } - return mUidTagComplete; - } - } - - @Override - public int[] getRelevantUids() { - return getUidComplete().getRelevantUids(mAccessLevel); - } - - @Override - public NetworkStats getDeviceSummaryForNetwork( - NetworkTemplate template, long start, long end) { - enforceTemplatePermissions(template, callingPackage); - return internalGetSummaryForNetwork(template, restrictedFlags, start, end, - mAccessLevel, mCallingUid); - } - - @Override - public NetworkStats getSummaryForNetwork( - NetworkTemplate template, long start, long end) { - enforceTemplatePermissions(template, callingPackage); - return internalGetSummaryForNetwork(template, restrictedFlags, start, end, - mAccessLevel, mCallingUid); - } - - // TODO: Remove this after all callers are removed. - @Override - public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { - enforceTemplatePermissions(template, callingPackage); - return internalGetHistoryForNetwork(template, restrictedFlags, fields, - mAccessLevel, mCallingUid, Long.MIN_VALUE, Long.MAX_VALUE); - } - - @Override - public NetworkStatsHistory getHistoryIntervalForNetwork(NetworkTemplate template, - int fields, long start, long end) { - enforceTemplatePermissions(template, callingPackage); - // TODO(b/200768422): Redact returned history if the template is location - // sensitive but the caller is not privileged. - return internalGetHistoryForNetwork(template, restrictedFlags, fields, - mAccessLevel, mCallingUid, start, end); - } - - @Override - public NetworkStats getSummaryForAllUid( - NetworkTemplate template, long start, long end, boolean includeTags) { - enforceTemplatePermissions(template, callingPackage); - try { - final NetworkStats stats = getUidComplete() - .getSummary(template, start, end, mAccessLevel, mCallingUid); - if (includeTags) { - final NetworkStats tagStats = getUidTagComplete() - .getSummary(template, start, end, mAccessLevel, mCallingUid); - stats.combineAllValues(tagStats); - } - return stats; - } catch (NullPointerException e) { - throw e; - } - } - - @Override - public NetworkStats getTaggedSummaryForAllUid( - NetworkTemplate template, long start, long end) { - enforceTemplatePermissions(template, callingPackage); - try { - final NetworkStats tagStats = getUidTagComplete() - .getSummary(template, start, end, mAccessLevel, mCallingUid); - return tagStats; - } catch (NullPointerException e) { - throw e; - } - } - - @Override - public NetworkStatsHistory getHistoryForUid( - NetworkTemplate template, int uid, int set, int tag, int fields) { - enforceTemplatePermissions(template, callingPackage); - // NOTE: We don't augment UID-level statistics - if (tag == TAG_NONE) { - return getUidComplete().getHistory(template, null, uid, set, tag, fields, - Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid); - } else { - return getUidTagComplete().getHistory(template, null, uid, set, tag, fields, - Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid); - } - } - - @Override - public NetworkStatsHistory getHistoryIntervalForUid( - NetworkTemplate template, int uid, int set, int tag, int fields, - long start, long end) { - enforceTemplatePermissions(template, callingPackage); - // TODO(b/200768422): Redact returned history if the template is location - // sensitive but the caller is not privileged. - // NOTE: We don't augment UID-level statistics - if (tag == TAG_NONE) { - return getUidComplete().getHistory(template, null, uid, set, tag, fields, - start, end, mAccessLevel, mCallingUid); - } else if (uid == Binder.getCallingUid()) { - return getUidTagComplete().getHistory(template, null, uid, set, tag, fields, - start, end, mAccessLevel, mCallingUid); - } else { - throw new SecurityException("Calling package " + mCallingPackage - + " cannot access tag information from a different uid"); - } - } - - @Override - public void close() { - mUidComplete = null; - mUidTagComplete = null; - } - }; - } - - private void enforceTemplatePermissions(@NonNull NetworkTemplate template, - @NonNull String callingPackage) { - // For a template with wifi network keys, it is possible for a malicious - // client to track the user locations via querying data usage. Thus, enforce - // fine location permission check. - if (!template.getWifiNetworkKeys().isEmpty()) { - final boolean canAccessFineLocation = mLocationPermissionChecker - .checkCallersLocationPermission(callingPackage, - null /* featureId */, - Binder.getCallingUid(), - false /* coarseForTargetSdkLessThanQ */, - null /* message */); - if (!canAccessFineLocation) { - throw new SecurityException("Access fine location is required when querying" - + " with wifi network keys, make sure the app has the necessary" - + "permissions and the location toggle is on."); - } - } - } - - private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) { - return NetworkStatsAccess.checkAccessLevel( - mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage); - } - - /** - * Find the most relevant {@link SubscriptionPlan} for the given - * {@link NetworkTemplate} and flags. This is typically used to augment - * local measurement results to match a known anchor from the carrier. - */ - private SubscriptionPlan resolveSubscriptionPlan(NetworkTemplate template, int flags) { - SubscriptionPlan plan = null; - if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0 - && mSettings.getAugmentEnabled()) { - if (LOGD) Log.d(TAG, "Resolving plan for " + template); - final long token = Binder.clearCallingIdentity(); - try { - plan = mContext.getSystemService(NetworkPolicyManager.class) - .getSubscriptionPlan(template); - } finally { - Binder.restoreCallingIdentity(token); - } - if (LOGD) Log.d(TAG, "Resolved to plan " + plan); - } - return plan; - } - - /** - * Return network summary, splicing between DEV and XT stats when - * appropriate. - */ - private NetworkStats internalGetSummaryForNetwork(NetworkTemplate template, int flags, - long start, long end, @NetworkStatsAccess.Level int accessLevel, int callingUid) { - // We've been using pure XT stats long enough that we no longer need to - // splice DEV and XT together. - final NetworkStatsHistory history = internalGetHistoryForNetwork(template, flags, FIELD_ALL, - accessLevel, callingUid, start, end); - - final long now = System.currentTimeMillis(); - final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); - - final NetworkStats stats = new NetworkStats(end - start, 1); - stats.insertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets, - entry.txBytes, entry.txPackets, entry.operations)); - return stats; - } - - /** - * Return network history, splicing between DEV and XT stats when - * appropriate. - */ - private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, - int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid, - long start, long end) { - // We've been using pure XT stats long enough that we no longer need to - // splice DEV and XT together. - final SubscriptionPlan augmentPlan = resolveSubscriptionPlan(template, flags); - synchronized (mStatsLock) { - return mXtStatsCached.getHistory(template, augmentPlan, - UID_ALL, SET_ALL, TAG_NONE, fields, start, end, accessLevel, callingUid); - } - } - - private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { - assertSystemReady(); - - return internalGetSummaryForNetwork(template, - NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end, - NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes(); - } - - private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) { - assertSystemReady(); - - final NetworkStatsCollection uidComplete; - synchronized (mStatsLock) { - uidComplete = mUidRecorder.getOrLoadCompleteLocked(); - } - return uidComplete.getSummary(template, start, end, NetworkStatsAccess.Level.DEVICE, - android.os.Process.SYSTEM_UID); - } - - @Override - public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException { - if (Binder.getCallingUid() != uid) { - Log.w(TAG, "Snapshots only available for calling UID"); - return new NetworkStats(SystemClock.elapsedRealtime(), 0); - } - - // TODO: switch to data layer stats once kernel exports - // for now, read network layer stats and flatten across all ifaces. - // This function is used to query NeworkStats for calle's uid. The only caller method - // TrafficStats#getDataLayerSnapshotForUid alrady claim no special permission to query - // its own NetworkStats. - final long ident = Binder.clearCallingIdentity(); - final NetworkStats networkLayer; - try { - networkLayer = readNetworkStatsUidDetail(uid, INTERFACES_ALL, TAG_ALL); - } finally { - Binder.restoreCallingIdentity(ident); - } - - // splice in operation counts - networkLayer.spliceOperationsFrom(mUidOperations); - - final NetworkStats dataLayer = new NetworkStats( - networkLayer.getElapsedRealtime(), networkLayer.size()); - - NetworkStats.Entry entry = null; - for (int i = 0; i < networkLayer.size(); i++) { - entry = networkLayer.getValues(i, entry); - entry.iface = IFACE_ALL; - dataLayer.combineValues(entry); - } - - return dataLayer; - } - - @Override - public NetworkStats getUidStatsForTransport(int transport) { - PermissionUtils.enforceNetworkStackPermission(mContext); - try { - final String[] relevantIfaces = - transport == TRANSPORT_WIFI ? mWifiIfaces : mMobileIfaces; - // TODO(b/215633405) : mMobileIfaces and mWifiIfaces already contain the stacked - // interfaces, so this is not useful, remove it. - final String[] ifacesToQuery = - mStatsFactory.augmentWithStackedInterfaces(relevantIfaces); - return getNetworkStatsUidDetail(ifacesToQuery); - } catch (RemoteException e) { - Log.wtf(TAG, "Error compiling UID stats", e); - return new NetworkStats(0L, 0); - } - } - - @Override - public String[] getMobileIfaces() { - // TODO (b/192758557): Remove debug log. - if (CollectionUtils.contains(mMobileIfaces, null)) { - throw new NullPointerException( - "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); - } - return mMobileIfaces.clone(); - } - - @Override - public void incrementOperationCount(int uid, int tag, int operationCount) { - if (Binder.getCallingUid() != uid) { - mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); - } - - if (operationCount < 0) { - throw new IllegalArgumentException("operation count can only be incremented"); - } - if (tag == TAG_NONE) { - throw new IllegalArgumentException("operation count must have specific tag"); - } - - synchronized (mStatsLock) { - final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT); - mUidOperations.combineValues( - mActiveIface, uid, set, tag, 0L, 0L, 0L, 0L, operationCount); - mUidOperations.combineValues( - mActiveIface, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount); - } - } - - private void setKernelCounterSet(int uid, int set) { - if (mUidCounterSetMap == null) { - Log.wtf(TAG, "Fail to set UidCounterSet: Null bpf map"); - return; - } - - if (set == SET_DEFAULT) { - try { - mUidCounterSetMap.deleteEntry(new U32(uid)); - } catch (ErrnoException e) { - Log.w(TAG, "UidCounterSetMap.deleteEntry(" + uid + ") failed with errno: " + e); - } - return; - } - - try { - mUidCounterSetMap.updateEntry(new U32(uid), new U8((short) set)); - } catch (ErrnoException e) { - Log.w(TAG, "UidCounterSetMap.updateEntry(" + uid + ", " + set - + ") failed with errno: " + e); - } - } - - @VisibleForTesting - public void noteUidForeground(int uid, boolean uidForeground) { - PermissionUtils.enforceNetworkStackPermission(mContext); - synchronized (mStatsLock) { - final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT; - final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT); - if (oldSet != set) { - mActiveUidCounterSet.put(uid, set); - setKernelCounterSet(uid, set); - } - } - } - - /** - * Notify {@code NetworkStatsService} about network status changed. - */ - public void notifyNetworkStatus( - @NonNull Network[] defaultNetworks, - @NonNull NetworkStateSnapshot[] networkStates, - @Nullable String activeIface, - @NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) { - PermissionUtils.enforceNetworkStackPermission(mContext); - - final long token = Binder.clearCallingIdentity(); - try { - handleNotifyNetworkStatus(defaultNetworks, networkStates, activeIface); - } finally { - Binder.restoreCallingIdentity(token); - } - - // Update the VPN underlying interfaces only after the poll is made and tun data has been - // migrated. Otherwise the migration would use the new interfaces instead of the ones that - // were current when the polled data was transferred. - mStatsFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos); - } - - @Override - public void forceUpdate() { - PermissionUtils.enforceNetworkStackPermission(mContext); - - final long token = Binder.clearCallingIdentity(); - try { - performPoll(FLAG_PERSIST_ALL); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** Advise persistence threshold; may be overridden internally. */ - public void advisePersistThreshold(long thresholdBytes) { - PermissionUtils.enforceNetworkStackPermission(mContext); - // clamp threshold into safe range - mPersistThreshold = NetworkStatsUtils.constrain(thresholdBytes, - 128 * KB_IN_BYTES, 2 * MB_IN_BYTES); - if (LOGV) { - Log.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to " - + mPersistThreshold); - } - - final long oldGlobalAlertBytes = mGlobalAlertBytes; - - // update and persist if beyond new thresholds - final long currentTime = mClock.millis(); - synchronized (mStatsLock) { - if (!mSystemReady) return; - - updatePersistThresholdsLocked(); - - mDevRecorder.maybePersistLocked(currentTime); - mXtRecorder.maybePersistLocked(currentTime); - mUidRecorder.maybePersistLocked(currentTime); - mUidTagRecorder.maybePersistLocked(currentTime); - } - - if (oldGlobalAlertBytes != mGlobalAlertBytes) { - registerGlobalAlert(); - } - } - - @Override - public DataUsageRequest registerUsageCallback(@NonNull String callingPackage, - @NonNull DataUsageRequest request, @NonNull IUsageCallback callback) { - Objects.requireNonNull(callingPackage, "calling package is null"); - Objects.requireNonNull(request, "DataUsageRequest is null"); - Objects.requireNonNull(request.template, "NetworkTemplate is null"); - Objects.requireNonNull(callback, "callback is null"); - - int callingUid = Binder.getCallingUid(); - @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage); - DataUsageRequest normalizedRequest; - final long token = Binder.clearCallingIdentity(); - try { - normalizedRequest = mStatsObservers.register(mContext, - request, callback, callingUid, accessLevel); - } finally { - Binder.restoreCallingIdentity(token); - } - - // Create baseline stats - mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL)); - - return normalizedRequest; - } - - @Override - public void unregisterUsageRequest(DataUsageRequest request) { - Objects.requireNonNull(request, "DataUsageRequest is null"); - - int callingUid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - mStatsObservers.unregister(request, callingUid); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public long getUidStats(int uid, int type) { - final int callingUid = Binder.getCallingUid(); - if (callingUid != android.os.Process.SYSTEM_UID && callingUid != uid) { - return UNSUPPORTED; - } - return nativeGetUidStat(uid, type); - } - - @Override - public long getIfaceStats(@NonNull String iface, int type) { - Objects.requireNonNull(iface); - long nativeIfaceStats = nativeGetIfaceStat(iface, type); - if (nativeIfaceStats == -1) { - return nativeIfaceStats; - } else { - // When tethering offload is in use, nativeIfaceStats does not contain usage from - // offload, add it back here. Note that the included statistics might be stale - // since polling newest stats from hardware might impact system health and not - // suitable for TrafficStats API use cases. - return nativeIfaceStats + getProviderIfaceStats(iface, type); - } - } - - @Override - public long getTotalStats(int type) { - long nativeTotalStats = nativeGetTotalStat(type); - if (nativeTotalStats == -1) { - return nativeTotalStats; - } else { - // Refer to comment in getIfaceStats - return nativeTotalStats + getProviderIfaceStats(IFACE_ALL, type); - } - } - - private long getProviderIfaceStats(@Nullable String iface, int type) { - final NetworkStats providerSnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE); - final HashSet limitIfaces; - if (iface == IFACE_ALL) { - limitIfaces = null; - } else { - limitIfaces = new HashSet<>(); - limitIfaces.add(iface); - } - final NetworkStats.Entry entry = providerSnapshot.getTotal(null, limitIfaces); - switch (type) { - case TrafficStats.TYPE_RX_BYTES: - return entry.rxBytes; - case TrafficStats.TYPE_RX_PACKETS: - return entry.rxPackets; - case TrafficStats.TYPE_TX_BYTES: - return entry.txBytes; - case TrafficStats.TYPE_TX_PACKETS: - return entry.txPackets; - default: - return 0; - } - } - - /** - * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to - * reflect current {@link #mPersistThreshold} value. Always defers to - * {@link Global} values when defined. - */ - @GuardedBy("mStatsLock") - private void updatePersistThresholdsLocked() { - mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold)); - mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold)); - mUidRecorder.setPersistThreshold(mSettings.getUidPersistBytes(mPersistThreshold)); - mUidTagRecorder.setPersistThreshold(mSettings.getUidTagPersistBytes(mPersistThreshold)); - mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold); - } - - /** - * Listener that watches for {@link TetheringManager} to claim interface pairs. - */ - private final TetheringManager.TetheringEventCallback mTetherListener = - new TetheringManager.TetheringEventCallback() { - @Override - public void onUpstreamChanged(@Nullable Network network) { - performPoll(FLAG_PERSIST_NETWORK); - } - }; - - private BroadcastReceiver mPollReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // on background handler thread, and verified UPDATE_DEVICE_STATS - // permission above. - performPoll(FLAG_PERSIST_ALL); - - // verify that we're watching global alert - registerGlobalAlert(); - } - }; - - private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // on background handler thread, and UID_REMOVED is protected - // broadcast. - - final int uid = intent.getIntExtra(EXTRA_UID, -1); - if (uid == -1) return; - - synchronized (mStatsLock) { - mWakeLock.acquire(); - try { - removeUidsLocked(uid); - } finally { - mWakeLock.release(); - } - } - } - }; - - private BroadcastReceiver mUserReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // On background handler thread, and USER_REMOVED is protected - // broadcast. - - final UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); - if (userHandle == null) return; - - synchronized (mStatsLock) { - mWakeLock.acquire(); - try { - removeUserLocked(userHandle); - } finally { - mWakeLock.release(); - } - } - } - }; - - private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // SHUTDOWN is protected broadcast. - synchronized (mStatsLock) { - shutdownLocked(); - } - } - }; - - /** - * Handle collapsed RAT type changed event. - */ - @VisibleForTesting - public void handleOnCollapsedRatTypeChanged() { - // Protect service from frequently updating. Remove pending messages if any. - mHandler.removeMessages(MSG_NOTIFY_NETWORK_STATUS); - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_NOTIFY_NETWORK_STATUS), mSettings.getPollDelay()); - } - - private void handleNotifyNetworkStatus( - Network[] defaultNetworks, - NetworkStateSnapshot[] snapshots, - String activeIface) { - synchronized (mStatsLock) { - mWakeLock.acquire(); - try { - mActiveIface = activeIface; - handleNotifyNetworkStatusLocked(defaultNetworks, snapshots); - } finally { - mWakeLock.release(); - } - } - } - - /** - * Inspect all current {@link NetworkStateSnapshot}s to derive mapping from {@code iface} to - * {@link NetworkStatsHistory}. When multiple networks are active on a single {@code iface}, - * they are combined under a single {@link NetworkIdentitySet}. - */ - @GuardedBy("mStatsLock") - private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks, - @NonNull NetworkStateSnapshot[] snapshots) { - if (!mSystemReady) return; - if (LOGV) Log.v(TAG, "handleNotifyNetworkStatusLocked()"); - - // take one last stats snapshot before updating iface mapping. this - // isn't perfect, since the kernel may already be counting traffic from - // the updated network. - - // poll, but only persist network stats to keep codepath fast. UID stats - // will be persisted during next alarm poll event. - performPollLocked(FLAG_PERSIST_NETWORK); - - // Rebuild active interfaces based on connected networks - mActiveIfaces.clear(); - mActiveUidIfaces.clear(); - // Update the list of default networks. - mDefaultNetworks = defaultNetworks; - - mLastNetworkStateSnapshots = snapshots; - - final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); - final ArraySet mobileIfaces = new ArraySet<>(); - final ArraySet wifiIfaces = new ArraySet<>(); - for (NetworkStateSnapshot snapshot : snapshots) { - final int displayTransport = - getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes()); - final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport); - final boolean isWifi = (NetworkCapabilities.TRANSPORT_WIFI == displayTransport); - final boolean isDefault = CollectionUtils.contains( - mDefaultNetworks, snapshot.getNetwork()); - final int ratType = combineSubtypeEnabled ? NetworkTemplate.NETWORK_TYPE_ALL - : getRatTypeForStateSnapshot(snapshot); - final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, - isDefault, ratType); - - // Traffic occurring on the base interface is always counted for - // both total usage and UID details. - final String baseIface = snapshot.getLinkProperties().getInterfaceName(); - if (baseIface != null) { - findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); - - // Build a separate virtual interface for VT (Video Telephony) data usage. - // Only do this when IMS is not metered, but VT is metered. - // If IMS is metered, then the IMS network usage has already included VT usage. - // VT is considered always metered in framework's layer. If VT is not metered - // per carrier's policy, modem will report 0 usage for VT calls. - if (snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.isMetered()) { - - // Copy the identify from IMS one but mark it as metered. - NetworkIdentity vtIdent = new NetworkIdentity.Builder() - .setType(ident.getType()) - .setRatType(ident.getRatType()) - .setSubscriberId(ident.getSubscriberId()) - .setWifiNetworkKey(ident.getWifiNetworkKey()) - .setRoaming(ident.isRoaming()).setMetered(true) - .setDefaultNetwork(true) - .setOemManaged(ident.getOemManaged()) - .setSubId(ident.getSubId()).build(); - final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot); - findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent); - } - - if (isMobile) { - mobileIfaces.add(baseIface); - } - if (isWifi) { - wifiIfaces.add(baseIface); - } - } - - // Traffic occurring on stacked interfaces is usually clatd. - // - // UID stats are always counted on the stacked interface and never on the base - // interface, because the packets on the base interface do not actually match - // application sockets (they're not IPv4) and thus the app uid is not known. - // For receive this is obvious: packets must be translated from IPv6 to IPv4 - // before the application socket can be found. - // For transmit: either they go through the clat daemon which by virtue of going - // through userspace strips the original socket association during the IPv4 to - // IPv6 translation process, or they are offloaded by eBPF, which doesn't: - // However, on an ebpf device the accounting is done in cgroup ebpf hooks, - // which don't trigger again post ebpf translation. - // (as such stats accounted to the clat uid are ignored) - // - // Interface stats are more complicated. - // - // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus - // *all* statistics are collected by iptables on the stacked v4-* interface. - // - // Additionally for ingress all packets bound for the clat IPv6 address are dropped - // in ip6tables raw prerouting and thus even non-offloaded packets are only - // accounted for on the stacked interface. - // - // For egress, packets subject to eBPF offload never appear on the base interface - // and only appear on the stacked interface. Thus to ensure packets increment - // interface stats, we must collate data from stacked interfaces. For xt_qtaguid - // (or non eBPF offloaded) TX they would appear on both, however egress interface - // accounting is explicitly bypassed for traffic from the clat uid. - // - // TODO: This code might be combined to above code. - for (String iface : snapshot.getLinkProperties().getAllInterfaceNames()) { - // baseIface has been handled, so ignore it. - if (TextUtils.equals(baseIface, iface)) continue; - if (iface != null) { - findOrCreateNetworkIdentitySet(mActiveIfaces, iface).add(ident); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident); - if (isMobile) { - mobileIfaces.add(iface); - } - if (isWifi) { - wifiIfaces.add(iface); - } - - mStatsFactory.noteStackedIface(iface, baseIface); - } - } - } - - mMobileIfaces = mobileIfaces.toArray(new String[0]); - mWifiIfaces = wifiIfaces.toArray(new String[0]); - // TODO (b/192758557): Remove debug log. - if (CollectionUtils.contains(mMobileIfaces, null)) { - throw new NullPointerException( - "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); - } - if (CollectionUtils.contains(mWifiIfaces, null)) { - throw new NullPointerException( - "null element in mWifiIfaces: " + Arrays.toString(mWifiIfaces)); - } - } - - private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { - if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR"); - } - - final NetworkSpecifier spec = state.getNetworkCapabilities().getNetworkSpecifier(); - if (spec instanceof TelephonyNetworkSpecifier) { - return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); - } else { - Log.wtf(TAG, "getSubIdForState invalid NetworkSpecifier"); - return INVALID_SUBSCRIPTION_ID; - } - } - - /** - * For networks with {@code TRANSPORT_CELLULAR}, get ratType that was obtained through - * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different - * transport types do not actually fill this value. - */ - private int getRatTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) { - if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - return 0; - } - - return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.getSubscriberId()); - } - - private static NetworkIdentitySet findOrCreateNetworkIdentitySet( - ArrayMap map, K key) { - NetworkIdentitySet ident = map.get(key); - if (ident == null) { - ident = new NetworkIdentitySet(); - map.put(key, ident); - } - return ident; - } - - @GuardedBy("mStatsLock") - private void recordSnapshotLocked(long currentTime) throws RemoteException { - // snapshot and record current counters; read UID stats first to - // avoid over counting dev stats. - Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotUid"); - final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL); - Trace.traceEnd(TRACE_TAG_NETWORK); - Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotXt"); - final NetworkStats xtSnapshot = readNetworkStatsSummaryXt(); - Trace.traceEnd(TRACE_TAG_NETWORK); - Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotDev"); - final NetworkStats devSnapshot = readNetworkStatsSummaryDev(); - Trace.traceEnd(TRACE_TAG_NETWORK); - - // Snapshot for dev/xt stats from all custom stats providers. Counts per-interface data - // from stats providers that isn't already counted by dev and XT stats. - Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotStatsProvider"); - final NetworkStats providersnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE); - Trace.traceEnd(TRACE_TAG_NETWORK); - xtSnapshot.combineAllValues(providersnapshot); - devSnapshot.combineAllValues(providersnapshot); - - // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic - // can't be reattributed to responsible apps. - Trace.traceBegin(TRACE_TAG_NETWORK, "recordDev"); - mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); - Trace.traceEnd(TRACE_TAG_NETWORK); - Trace.traceBegin(TRACE_TAG_NETWORK, "recordXt"); - mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); - Trace.traceEnd(TRACE_TAG_NETWORK); - - // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. - Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); - mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); - Trace.traceEnd(TRACE_TAG_NETWORK); - Trace.traceBegin(TRACE_TAG_NETWORK, "recordUidTag"); - mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); - Trace.traceEnd(TRACE_TAG_NETWORK); - - // We need to make copies of member fields that are sent to the observer to avoid - // a race condition between the service handler thread and the observer's - mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), - new ArrayMap<>(mActiveUidIfaces), currentTime); - } - - /** - * Bootstrap initial stats snapshot, usually during {@link #systemReady()} - * so we have baseline values without double-counting. - */ - @GuardedBy("mStatsLock") - private void bootstrapStatsLocked() { - final long currentTime = mClock.millis(); - - try { - recordSnapshotLocked(currentTime); - } catch (IllegalStateException e) { - Log.w(TAG, "problem reading network stats: " + e); - } catch (RemoteException e) { - // ignored; service lives in system_server - } - } - - private void performPoll(int flags) { - synchronized (mStatsLock) { - mWakeLock.acquire(); - - try { - performPollLocked(flags); - } finally { - mWakeLock.release(); - } - } - } - - /** - * Periodic poll operation, reading current statistics and recording into - * {@link NetworkStatsHistory}. - */ - @GuardedBy("mStatsLock") - private void performPollLocked(int flags) { - if (!mSystemReady) return; - if (LOGV) Log.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); - Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked"); - - final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; - final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; - final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; - - performPollFromProvidersLocked(); - - // TODO: consider marking "untrusted" times in historical stats - final long currentTime = mClock.millis(); - - try { - recordSnapshotLocked(currentTime); - } catch (IllegalStateException e) { - Log.wtf(TAG, "problem reading network stats", e); - return; - } catch (RemoteException e) { - // ignored; service lives in system_server - return; - } - - // persist any pending data depending on requested flags - Trace.traceBegin(TRACE_TAG_NETWORK, "[persisting]"); - if (persistForce) { - mDevRecorder.forcePersistLocked(currentTime); - mXtRecorder.forcePersistLocked(currentTime); - mUidRecorder.forcePersistLocked(currentTime); - mUidTagRecorder.forcePersistLocked(currentTime); - } else { - if (persistNetwork) { - mDevRecorder.maybePersistLocked(currentTime); - mXtRecorder.maybePersistLocked(currentTime); - } - if (persistUid) { - mUidRecorder.maybePersistLocked(currentTime); - mUidTagRecorder.maybePersistLocked(currentTime); - } - } - Trace.traceEnd(TRACE_TAG_NETWORK); - - if (mSettings.getSampleEnabled()) { - // sample stats after each full poll - performSampleLocked(); - } - - // finally, dispatch updated event to any listeners - mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED)); - - Trace.traceEnd(TRACE_TAG_NETWORK); - } - - @GuardedBy("mStatsLock") - private void performPollFromProvidersLocked() { - // Request asynchronous stats update from all providers for next poll. And wait a bit of - // time to allow providers report-in given that normally binder call should be fast. Note - // that size of list might be changed because addition/removing at the same time. For - // addition, the stats of the missed provider can only be collected in next poll; - // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS - // once that happened. - // TODO: request with a valid token. - Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); - final int registeredCallbackCount = mStatsProviderCbList.size(); - mStatsProviderSem.drainPermits(); - invokeForAllStatsProviderCallbacks( - (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); - try { - mStatsProviderSem.tryAcquire(registeredCallbackCount, - MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - // Strictly speaking it's possible a provider happened to deliver between the timeout - // and the log, and that doesn't matter too much as this is just a debug log. - Log.d(TAG, "requestStatsUpdate - providers responded " - + mStatsProviderSem.availablePermits() - + "/" + registeredCallbackCount + " : " + e); - } - Trace.traceEnd(TRACE_TAG_NETWORK); - } - - /** - * Sample recent statistics summary into {@link EventLog}. - */ - @GuardedBy("mStatsLock") - private void performSampleLocked() { - // TODO: migrate trustedtime fixes to separate binary log events - final long currentTime = mClock.millis(); - - NetworkTemplate template; - NetworkStats.Entry devTotal; - NetworkStats.Entry xtTotal; - NetworkStats.Entry uidTotal; - - // collect mobile sample - template = buildTemplateMobileWildcard(); - devTotal = mDevRecorder.getTotalSinceBootLocked(template); - xtTotal = mXtRecorder.getTotalSinceBootLocked(template); - uidTotal = mUidRecorder.getTotalSinceBootLocked(template); - - EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE, - devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, - xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, - uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - currentTime); - - // collect wifi sample - template = buildTemplateWifiWildcard(); - devTotal = mDevRecorder.getTotalSinceBootLocked(template); - xtTotal = mXtRecorder.getTotalSinceBootLocked(template); - uidTotal = mUidRecorder.getTotalSinceBootLocked(template); - - EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE, - devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, - xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, - uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - currentTime); - } - - // deleteKernelTagData can ignore ENOENT; otherwise we should log an error - private void logErrorIfNotErrNoent(final ErrnoException e, final String msg) { - if (e.errno != ENOENT) Log.e(TAG, msg, e); - } - - private void deleteStatsMapTagData( - IBpfMap statsMap, int uid) { - try { - statsMap.forEach((key, value) -> { - if (key.uid == uid) { - try { - statsMap.deleteEntry(key); - } catch (ErrnoException e) { - logErrorIfNotErrNoent(e, "Failed to delete data(uid = " + key.uid + ")"); - } - } - }); - } catch (ErrnoException e) { - Log.e(TAG, "FAILED to delete tag data from stats map", e); - } - } - - /** - * Deletes uid tag data from CookieTagMap, StatsMapA, StatsMapB, and UidStatsMap - * @param uid - */ - private void deleteKernelTagData(int uid) { - try { - mCookieTagMap.forEach((key, value) -> { - // If SkDestroyListener deletes the socket tag while this code is running, - // forEach will either restart iteration from the beginning or return null, - // depending on when the deletion happens. - // If it returns null, continue iteration to delete the data and in fact it would - // just iterate from first key because BpfMap#getNextKey would return first key - // if the current key is not exist. - if (value != null && value.uid == uid) { - try { - mCookieTagMap.deleteEntry(key); - } catch (ErrnoException e) { - logErrorIfNotErrNoent(e, "Failed to delete data(cookie = " + key + ")"); - } - } - }); - } catch (ErrnoException e) { - Log.e(TAG, "Failed to delete tag data from cookie tag map", e); - } - - deleteStatsMapTagData(mStatsMapA, uid); - deleteStatsMapTagData(mStatsMapB, uid); - - try { - mUidCounterSetMap.deleteEntry(new U32(uid)); - } catch (ErrnoException e) { - logErrorIfNotErrNoent(e, "Failed to delete tag data from uid counter set map"); - } - - try { - mAppUidStatsMap.deleteEntry(new UidStatsMapKey(uid)); - } catch (ErrnoException e) { - logErrorIfNotErrNoent(e, "Failed to delete tag data from app uid stats map"); - } - } - - /** - * Clean up {@link #mUidRecorder} after UID is removed. - */ - @GuardedBy("mStatsLock") - private void removeUidsLocked(int... uids) { - if (LOGV) Log.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids)); - - // Perform one last poll before removing - performPollLocked(FLAG_PERSIST_ALL); - - mUidRecorder.removeUidsLocked(uids); - mUidTagRecorder.removeUidsLocked(uids); - - // Clear kernel stats associated with UID - for (int uid : uids) { - deleteKernelTagData(uid); - } - } - - /** - * Clean up {@link #mUidRecorder} after user is removed. - */ - @GuardedBy("mStatsLock") - private void removeUserLocked(@NonNull UserHandle userHandle) { - if (LOGV) Log.v(TAG, "removeUserLocked() for UserHandle=" + userHandle); - - // Build list of UIDs that we should clean up - final ArrayList uids = new ArrayList<>(); - final List apps = mContext.getPackageManager().getInstalledApplications( - PackageManager.MATCH_ANY_USER - | PackageManager.MATCH_DISABLED_COMPONENTS); - for (ApplicationInfo app : apps) { - final int uid = userHandle.getUid(app.uid); - uids.add(uid); - } - - removeUidsLocked(CollectionUtils.toIntArray(uids)); - } - - /** - * Set the warning and limit to all registered custom network stats providers. - * Note that invocation of any interface will be sent to all providers. - */ - public void setStatsProviderWarningAndLimitAsync( - @NonNull String iface, long warning, long limit) { - PermissionUtils.enforceNetworkStackPermission(mContext); - if (LOGV) { - Log.v(TAG, "setStatsProviderWarningAndLimitAsync(" - + iface + "," + warning + "," + limit + ")"); - } - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, - warning, limit)); - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) { - if (!PermissionUtils.checkDumpPermission(mContext, TAG, rawWriter)) return; - - long duration = DateUtils.DAY_IN_MILLIS; - final HashSet argSet = new HashSet(); - for (String arg : args) { - argSet.add(arg); - - if (arg.startsWith("--duration=")) { - try { - duration = Long.parseLong(arg.substring(11)); - } catch (NumberFormatException ignored) { - } - } - } - - // usage: dumpsys netstats --full --uid --tag --poll --checkin - final boolean poll = argSet.contains("--poll") || argSet.contains("poll"); - final boolean checkin = argSet.contains("--checkin"); - final boolean fullHistory = argSet.contains("--full") || argSet.contains("full"); - final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail"); - final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail"); - - final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " "); - - synchronized (mStatsLock) { - if (args.length > 0 && "--proto".equals(args[0])) { - // In this case ignore all other arguments. - dumpProtoLocked(fd); - return; - } - - if (poll) { - performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE); - pw.println("Forced poll"); - return; - } - - if (checkin) { - final long end = System.currentTimeMillis(); - final long start = end - duration; - - pw.print("v1,"); - pw.print(start / SECOND_IN_MILLIS); pw.print(','); - pw.print(end / SECOND_IN_MILLIS); pw.println(); - - pw.println("xt"); - mXtRecorder.dumpCheckin(rawWriter, start, end); - - if (includeUid) { - pw.println("uid"); - mUidRecorder.dumpCheckin(rawWriter, start, end); - } - if (includeTag) { - pw.println("tag"); - mUidTagRecorder.dumpCheckin(rawWriter, start, end); - } - return; - } - - pw.println("Configs:"); - pw.increaseIndent(); - pw.print(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled()); - pw.println(); - pw.decreaseIndent(); - - pw.println("Active interfaces:"); - pw.increaseIndent(); - for (int i = 0; i < mActiveIfaces.size(); i++) { - pw.print("iface", mActiveIfaces.keyAt(i)); - pw.print("ident", mActiveIfaces.valueAt(i)); - pw.println(); - } - pw.decreaseIndent(); - - pw.println("Active UID interfaces:"); - pw.increaseIndent(); - for (int i = 0; i < mActiveUidIfaces.size(); i++) { - pw.print("iface", mActiveUidIfaces.keyAt(i)); - pw.print("ident", mActiveUidIfaces.valueAt(i)); - pw.println(); - } - pw.decreaseIndent(); - - // Get the top openSession callers - final SparseIntArray calls; - synchronized (mOpenSessionCallsPerUid) { - calls = mOpenSessionCallsPerUid.clone(); - } - - final int N = calls.size(); - final long[] values = new long[N]; - for (int j = 0; j < N; j++) { - values[j] = ((long) calls.valueAt(j) << 32) | calls.keyAt(j); - } - Arrays.sort(values); - - pw.println("Top openSession callers (uid=count):"); - pw.increaseIndent(); - final int end = Math.max(0, N - DUMP_STATS_SESSION_COUNT); - for (int j = N - 1; j >= end; j--) { - final int uid = (int) (values[j] & 0xffffffff); - final int count = (int) (values[j] >> 32); - pw.print(uid); pw.print("="); pw.println(count); - } - pw.decreaseIndent(); - pw.println(); - - pw.println("Stats Providers:"); - pw.increaseIndent(); - invokeForAllStatsProviderCallbacks((cb) -> { - pw.println(cb.mTag + " Xt:"); - pw.increaseIndent(); - pw.print(cb.getCachedStats(STATS_PER_IFACE).toString()); - pw.decreaseIndent(); - if (includeUid) { - pw.println(cb.mTag + " Uid:"); - pw.increaseIndent(); - pw.print(cb.getCachedStats(STATS_PER_UID).toString()); - pw.decreaseIndent(); - } - }); - pw.decreaseIndent(); - - pw.println("Dev stats:"); - pw.increaseIndent(); - mDevRecorder.dumpLocked(pw, fullHistory); - pw.decreaseIndent(); - - pw.println("Xt stats:"); - pw.increaseIndent(); - mXtRecorder.dumpLocked(pw, fullHistory); - pw.decreaseIndent(); - - if (includeUid) { - pw.println("UID stats:"); - pw.increaseIndent(); - mUidRecorder.dumpLocked(pw, fullHistory); - pw.decreaseIndent(); - } - - if (includeTag) { - pw.println("UID tag stats:"); - pw.increaseIndent(); - mUidTagRecorder.dumpLocked(pw, fullHistory); - pw.decreaseIndent(); - } - } - } - - @GuardedBy("mStatsLock") - private void dumpProtoLocked(FileDescriptor fd) { - final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd)); - - // TODO Right now it writes all history. Should it limit to the "since-boot" log? - - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, - mActiveIfaces); - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, - mActiveUidIfaces); - mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); - mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); - mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); - mUidTagRecorder.dumpDebugLocked(proto, - NetworkStatsServiceDumpProto.UID_TAG_STATS); - - proto.flush(); - } - - private static void dumpInterfaces(ProtoOutputStream proto, long tag, - ArrayMap ifaces) { - for (int i = 0; i < ifaces.size(); i++) { - final long start = proto.start(tag); - - proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); - ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES); - - proto.end(start); - } - } - - private NetworkStats readNetworkStatsSummaryDev() { - try { - return mStatsFactory.readNetworkStatsSummaryDev(); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private NetworkStats readNetworkStatsSummaryXt() { - try { - return mStatsFactory.readNetworkStatsSummaryXt(); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private NetworkStats readNetworkStatsUidDetail(int uid, String[] ifaces, int tag) { - try { - return mStatsFactory.readNetworkStatsDetail(uid, ifaces, tag); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - /** - * Return snapshot of current UID statistics, including any - * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations} - * values. - * - * @param ifaces A list of interfaces the stats should be restricted to, or - * {@link NetworkStats#INTERFACES_ALL}. - */ - private NetworkStats getNetworkStatsUidDetail(String[] ifaces) - throws RemoteException { - final NetworkStats uidSnapshot = readNetworkStatsUidDetail(UID_ALL, ifaces, TAG_ALL); - - // fold tethering stats and operations into uid snapshot - final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); - tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); - uidSnapshot.combineAllValues(tetherSnapshot); - - // get a stale copy of uid stats snapshot provided by providers. - final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID); - providerStats.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats); - uidSnapshot.combineAllValues(providerStats); - - uidSnapshot.combineAllValues(mUidOperations); - - return uidSnapshot; - } - - /** - * Return snapshot of current non-offloaded tethering statistics. Will return empty - * {@link NetworkStats} if any problems are encountered, or queried by {@code STATS_PER_IFACE} - * since it is already included by {@link #nativeGetIfaceStat}. - * See {@code OffloadTetheringStatsProvider} for offloaded tethering stats. - */ - // TODO: Remove this by implementing {@link NetworkStatsProvider} for non-offloaded - // tethering stats. - private @NonNull NetworkStats getNetworkStatsTethering(int how) throws RemoteException { - // We only need to return per-UID stats. Per-device stats are already counted by - // interface counters. - if (how != STATS_PER_UID) { - return new NetworkStats(SystemClock.elapsedRealtime(), 0); - } - - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); - try { - final TetherStatsParcel[] tetherStatsParcels = mNetd.tetherGetStats(); - for (TetherStatsParcel tetherStats : tetherStatsParcels) { - try { - stats.combineValues(new NetworkStats.Entry(tetherStats.iface, UID_TETHERING, - SET_DEFAULT, TAG_NONE, tetherStats.rxBytes, tetherStats.rxPackets, - tetherStats.txBytes, tetherStats.txPackets, 0L)); - } catch (ArrayIndexOutOfBoundsException e) { - throw new IllegalStateException("invalid tethering stats " + e); - } - } - } catch (IllegalStateException e) { - Log.wtf(TAG, "problem reading network stats", e); - } - return stats; - } - - // TODO: It is copied from ConnectivityService, consider refactor these check permission - // functions to a proper util. - private boolean checkAnyPermissionOf(String... permissions) { - for (String permission : permissions) { - if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { - return true; - } - } - return false; - } - - private void enforceAnyPermissionOf(String... permissions) { - if (!checkAnyPermissionOf(permissions)) { - throw new SecurityException("Requires one of the following permissions: " - + String.join(", ", permissions) + "."); - } - } - - /** - * Registers a custom provider of {@link android.net.NetworkStats} to combine the network - * statistics that cannot be seen by the kernel to system. To unregister, invoke the - * {@code unregister()} of the returned callback. - * - * @param tag a human readable identifier of the custom network stats provider. - * @param provider the {@link INetworkStatsProvider} binder corresponding to the - * {@link NetworkStatsProvider} to be registered. - * - * @return a {@link INetworkStatsProviderCallback} binder - * interface, which can be used to report events to the system. - */ - public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( - @NonNull String tag, @NonNull INetworkStatsProvider provider) { - enforceAnyPermissionOf(NETWORK_STATS_PROVIDER, - NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); - Objects.requireNonNull(provider, "provider is null"); - Objects.requireNonNull(tag, "tag is null"); - final NetworkPolicyManager netPolicyManager = mContext - .getSystemService(NetworkPolicyManager.class); - try { - NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( - tag, provider, mStatsProviderSem, mAlertObserver, - mStatsProviderCbList, netPolicyManager); - mStatsProviderCbList.add(callback); - Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" - + getCallingUid() + "/" + getCallingPid()); - return callback; - } catch (RemoteException e) { - Log.e(TAG, "registerNetworkStatsProvider failed", e); - } - return null; - } - - // Collect stats from local cache of providers. - private @NonNull NetworkStats getNetworkStatsFromProviders(int how) { - final NetworkStats ret = new NetworkStats(0L, 0); - invokeForAllStatsProviderCallbacks((cb) -> ret.combineAllValues(cb.getCachedStats(how))); - return ret; - } - - @FunctionalInterface - private interface ThrowingConsumer { - void accept(S s) throws T; - } - - private void invokeForAllStatsProviderCallbacks( - @NonNull ThrowingConsumer task) { - for (final NetworkStatsProviderCallbackImpl cb : mStatsProviderCbList) { - try { - task.accept(cb); - } catch (RemoteException e) { - Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); - } - } - } - - private static class NetworkStatsProviderCallbackImpl extends INetworkStatsProviderCallback.Stub - implements IBinder.DeathRecipient { - @NonNull final String mTag; - - @NonNull final INetworkStatsProvider mProvider; - @NonNull private final Semaphore mSemaphore; - @NonNull final AlertObserver mAlertObserver; - @NonNull final CopyOnWriteArrayList mStatsProviderCbList; - @NonNull final NetworkPolicyManager mNetworkPolicyManager; - - @NonNull private final Object mProviderStatsLock = new Object(); - - @GuardedBy("mProviderStatsLock") - // Track STATS_PER_IFACE and STATS_PER_UID separately. - private final NetworkStats mIfaceStats = new NetworkStats(0L, 0); - @GuardedBy("mProviderStatsLock") - private final NetworkStats mUidStats = new NetworkStats(0L, 0); - - NetworkStatsProviderCallbackImpl( - @NonNull String tag, @NonNull INetworkStatsProvider provider, - @NonNull Semaphore semaphore, - @NonNull AlertObserver alertObserver, - @NonNull CopyOnWriteArrayList cbList, - @NonNull NetworkPolicyManager networkPolicyManager) - throws RemoteException { - mTag = tag; - mProvider = provider; - mProvider.asBinder().linkToDeath(this, 0); - mSemaphore = semaphore; - mAlertObserver = alertObserver; - mStatsProviderCbList = cbList; - mNetworkPolicyManager = networkPolicyManager; - } - - @NonNull - public NetworkStats getCachedStats(int how) { - synchronized (mProviderStatsLock) { - NetworkStats stats; - switch (how) { - case STATS_PER_IFACE: - stats = mIfaceStats; - break; - case STATS_PER_UID: - stats = mUidStats; - break; - default: - throw new IllegalArgumentException("Invalid type: " + how); - } - // Callers might be able to mutate the returned object. Return a defensive copy - // instead of local reference. - return stats.clone(); - } - } - - @Override - public void notifyStatsUpdated(int token, @Nullable NetworkStats ifaceStats, - @Nullable NetworkStats uidStats) { - // TODO: 1. Use token to map ifaces to correct NetworkIdentity. - // 2. Store the difference and store it directly to the recorder. - synchronized (mProviderStatsLock) { - if (ifaceStats != null) mIfaceStats.combineAllValues(ifaceStats); - if (uidStats != null) mUidStats.combineAllValues(uidStats); - } - mSemaphore.release(); - } - - @Override - public void notifyAlertReached() throws RemoteException { - // This binder object can only have been obtained by a process that holds - // NETWORK_STATS_PROVIDER. Thus, no additional permission check is required. - BinderUtils.withCleanCallingIdentity(() -> - mAlertObserver.onQuotaLimitReached(LIMIT_GLOBAL_ALERT, null /* unused */)); - } - - @Override - public void notifyWarningReached() { - Log.d(TAG, mTag + ": notifyWarningReached"); - BinderUtils.withCleanCallingIdentity(() -> - mNetworkPolicyManager.notifyStatsProviderWarningReached()); - } - - @Override - public void notifyLimitReached() { - Log.d(TAG, mTag + ": notifyLimitReached"); - BinderUtils.withCleanCallingIdentity(() -> - mNetworkPolicyManager.notifyStatsProviderLimitReached()); - } - - @Override - public void binderDied() { - Log.d(TAG, mTag + ": binderDied"); - mStatsProviderCbList.remove(this); - } - - @Override - public void unregister() { - Log.d(TAG, mTag + ": unregister"); - mStatsProviderCbList.remove(this); - } - - } - - private void assertSystemReady() { - if (!mSystemReady) { - throw new IllegalStateException("System not ready"); - } - } - - private class DropBoxNonMonotonicObserver implements NonMonotonicObserver { - @Override - public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right, - int rightIndex, String cookie) { - Log.w(TAG, "Found non-monotonic values; saving to dropbox"); - - // record error for debugging - final StringBuilder builder = new StringBuilder(); - builder.append("found non-monotonic " + cookie + " values at left[" + leftIndex - + "] - right[" + rightIndex + "]\n"); - builder.append("left=").append(left).append('\n'); - builder.append("right=").append(right).append('\n'); - - mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR, - builder.toString()); - } - - @Override - public void foundNonMonotonic( - NetworkStats stats, int statsIndex, String cookie) { - Log.w(TAG, "Found non-monotonic values; saving to dropbox"); - - final StringBuilder builder = new StringBuilder(); - builder.append("Found non-monotonic " + cookie + " values at [" + statsIndex + "]\n"); - builder.append("stats=").append(stats).append('\n'); - - mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR, - builder.toString()); - } - } - - /** - * Default external settings that read from - * {@link android.provider.Settings.Global}. - */ - private static class DefaultNetworkStatsSettings implements NetworkStatsSettings { - DefaultNetworkStatsSettings() {} - - @Override - public long getPollInterval() { - return 30 * MINUTE_IN_MILLIS; - } - @Override - public long getPollDelay() { - return DEFAULT_PERFORM_POLL_DELAY_MS; - } - @Override - public long getGlobalAlertBytes(long def) { - return def; - } - @Override - public boolean getSampleEnabled() { - return true; - } - @Override - public boolean getAugmentEnabled() { - return true; - } - @Override - public boolean getCombineSubtypeEnabled() { - return false; - } - @Override - public Config getDevConfig() { - return new Config(HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); - } - @Override - public Config getXtConfig() { - return getDevConfig(); - } - @Override - public Config getUidConfig() { - return new Config(2 * HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); - } - @Override - public Config getUidTagConfig() { - return new Config(2 * HOUR_IN_MILLIS, 5 * DAY_IN_MILLIS, 15 * DAY_IN_MILLIS); - } - @Override - public long getDevPersistBytes(long def) { - return def; - } - @Override - public long getXtPersistBytes(long def) { - return def; - } - @Override - public long getUidPersistBytes(long def) { - return def; - } - @Override - public long getUidTagPersistBytes(long def) { - return def; - } - } - - private static native long nativeGetTotalStat(int type); - private static native long nativeGetIfaceStat(String iface, int type); - private static native long nativeGetUidStat(int uid, int type); -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java deleted file mode 100644 index 65ccd20072998..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * 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.server.net; - -import static android.app.usage.NetworkStatsManager.NETWORK_TYPE_5G_NSA; -import static android.app.usage.NetworkStatsManager.getCollapsedRatType; -import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED; -import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA; -import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; - -import android.annotation.NonNull; -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyCallback; -import android.telephony.TelephonyDisplayInfo; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Log; -import android.util.Pair; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; - -/** - * Helper class that watches for events that are triggered per subscription. - */ -@TargetApi(Build.VERSION_CODES.TIRAMISU) -public class NetworkStatsSubscriptionsMonitor extends - SubscriptionManager.OnSubscriptionsChangedListener { - - /** - * Interface that this monitor uses to delegate event handling to NetworkStatsService. - */ - public interface Delegate { - /** - * Notify that the collapsed RAT type has been changed for any subscription. The method - * will also be triggered for any existing sub when start and stop monitoring. - * - * @param subscriberId IMSI of the subscription. - * @param collapsedRatType collapsed RAT type. - * @see android.app.usage.NetworkStatsManager#getCollapsedRatType(int). - */ - void onCollapsedRatTypeChanged(@NonNull String subscriberId, int collapsedRatType); - } - private final Delegate mDelegate; - - /** - * Receivers that watches for {@link TelephonyDisplayInfo} changes for each subscription, to - * monitor the transitioning between Radio Access Technology(RAT) types for each sub. - */ - @NonNull - private final CopyOnWriteArrayList mRatListeners = - new CopyOnWriteArrayList<>(); - - @NonNull - private final SubscriptionManager mSubscriptionManager; - @NonNull - private final TelephonyManager mTeleManager; - - @NonNull - private final Executor mExecutor; - - NetworkStatsSubscriptionsMonitor(@NonNull Context context, - @NonNull Executor executor, @NonNull Delegate delegate) { - super(); - mSubscriptionManager = (SubscriptionManager) context.getSystemService( - Context.TELEPHONY_SUBSCRIPTION_SERVICE); - mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - mExecutor = executor; - mDelegate = delegate; - } - - @Override - public void onSubscriptionsChanged() { - // Collect active subId list, hidden subId such as opportunistic subscriptions are - // also needed to track CBRS. - final List newSubs = getActiveSubIdList(mSubscriptionManager); - - // IMSI is needed for every newly added sub. Listener stores subscriberId into it to - // prevent binder call to telephony when querying RAT. Keep listener registration with empty - // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported - // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration. - final List> filteredNewSubs = new ArrayList<>(); - for (final int subId : newSubs) { - final String subscriberId = - mTeleManager.createForSubscriptionId(subId).getSubscriberId(); - if (!TextUtils.isEmpty(subscriberId)) { - filteredNewSubs.add(new Pair(subId, subscriberId)); - } - } - - for (final Pair sub : filteredNewSubs) { - // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be - // suddenly change regardless of subId, such as switch IMSI feature in modem side. - // If that happens, register new listener with new IMSI and remove old one later. - if (CollectionUtils.any(mRatListeners, it -> it.equalsKey(sub.first, sub.second))) { - continue; - } - - final RatTypeListener listener = new RatTypeListener(this, sub.first, sub.second); - mRatListeners.add(listener); - - // Register listener to the telephony manager that associated with specific sub. - mTeleManager.createForSubscriptionId(sub.first) - .registerTelephonyCallback(mExecutor, listener); - Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first); - } - - for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { - // If there is no subId and IMSI matched the listener, removes it. - if (!CollectionUtils.any(filteredNewSubs, - it -> listener.equalsKey(it.first, it.second))) { - handleRemoveRatTypeListener(listener); - } - } - } - - @NonNull - private List getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) { - final ArrayList ret = new ArrayList<>(); - final int[] ids = subscriptionManager.getCompleteActiveSubscriptionIdList(); - for (int id : ids) ret.add(id); - return ret; - } - - /** - * Get a collapsed RatType for the given subscriberId. - * - * @param subscriberId the target subscriberId - * @return collapsed RatType for the given subscriberId - */ - public int getRatTypeForSubscriberId(@NonNull String subscriberId) { - final int index = CollectionUtils.indexOf(mRatListeners, - it -> TextUtils.equals(subscriberId, it.mSubscriberId)); - return index != -1 ? mRatListeners.get(index).mLastCollapsedRatType - : TelephonyManager.NETWORK_TYPE_UNKNOWN; - } - - /** - * Start monitoring events that triggered per subscription. - */ - public void start() { - mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, this); - } - - /** - * Unregister subscription changes and all listeners for each subscription. - */ - public void stop() { - mSubscriptionManager.removeOnSubscriptionsChangedListener(this); - - for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { - handleRemoveRatTypeListener(listener); - } - } - - private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { - mTeleManager.createForSubscriptionId(listener.mSubId) - .unregisterTelephonyCallback(listener); - Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId); - mRatListeners.remove(listener); - - // Removal of subscriptions doesn't generate RAT changed event, fire it for every - // RatTypeListener. - mDelegate.onCollapsedRatTypeChanged( - listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN); - } - - static class RatTypeListener extends TelephonyCallback - implements TelephonyCallback.DisplayInfoListener { - // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}. - @NonNull - private final int mSubId; - - // IMSI to identifying the corresponding network from {@link NetworkState}. - // See {@link TelephonyManager#getSubscriberId}. - @NonNull - private final String mSubscriberId; - - private volatile int mLastCollapsedRatType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - @NonNull - private final NetworkStatsSubscriptionsMonitor mMonitor; - - RatTypeListener(@NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, - @NonNull String subscriberId) { - mSubId = subId; - mSubscriberId = subscriberId; - mMonitor = monitor; - } - - @Override - public void onDisplayInfoChanged(TelephonyDisplayInfo displayInfo) { - // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony - // would report RAT = 5G_NR. - // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and - // network allocates a secondary 5G cell so telephony reports RAT = LTE along with - // NR state as connected. In such case, attributes the data usage to NR. - // See b/160727498. - final boolean is5GNsa = displayInfo.getNetworkType() == NETWORK_TYPE_LTE - && (displayInfo.getOverrideNetworkType() == OVERRIDE_NETWORK_TYPE_NR_NSA - || displayInfo.getOverrideNetworkType() == OVERRIDE_NETWORK_TYPE_NR_ADVANCED); - - final int networkType = - (is5GNsa ? NETWORK_TYPE_5G_NSA : displayInfo.getNetworkType()); - final int collapsedRatType = getCollapsedRatType(networkType); - if (collapsedRatType == mLastCollapsedRatType) return; - - if (NetworkStatsService.LOGD) { - Log.d(NetworkStatsService.TAG, "subtype changed for sub(" + mSubId + "): " - + mLastCollapsedRatType + " -> " + collapsedRatType); - } - mLastCollapsedRatType = collapsedRatType; - mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); - } - - @VisibleForTesting - public int getSubId() { - return mSubId; - } - - boolean equalsKey(int subId, @NonNull String subscriberId) { - return mSubId == subId && TextUtils.equals(mSubscriberId, subscriberId); - } - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java deleted file mode 100644 index ea8d836383477..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapKey.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * Key for both stats maps. - */ -public class StatsMapKey extends Struct { - @Field(order = 0, type = Type.U32) - public final long uid; - - @Field(order = 1, type = Type.U32) - public final long tag; - - @Field(order = 2, type = Type.U32) - public final long counterSet; - - @Field(order = 3, type = Type.U32) - public final long ifaceIndex; - - public StatsMapKey(final long uid, final long tag, final long counterSet, - final long ifaceIndex) { - this.uid = uid; - this.tag = tag; - this.counterSet = counterSet; - this.ifaceIndex = ifaceIndex; - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java b/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java deleted file mode 100644 index 48f26ce686e26..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/StatsMapValue.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * Value used for both stats maps and uid stats map. - */ -public class StatsMapValue extends Struct { - @Field(order = 0, type = Type.U63) - public final long rxPackets; - - @Field(order = 1, type = Type.U63) - public final long rxBytes; - - @Field(order = 2, type = Type.U63) - public final long txPackets; - - @Field(order = 3, type = Type.U63) - public final long txBytes; - - public StatsMapValue(final long rxPackets, final long rxBytes, final long txPackets, - final long txBytes) { - this.rxPackets = rxPackets; - this.rxBytes = rxBytes; - this.txPackets = txPackets; - this.txBytes = txBytes; - } -} diff --git a/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java b/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java deleted file mode 100644 index 2849f94c9383b..0000000000000 --- a/packages/ConnectivityT/service/src/com/android/server/net/UidStatsMapKey.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * Key for uid stats map. - */ -public class UidStatsMapKey extends Struct { - @Field(order = 0, type = Type.U32) - public final long uid; - - public UidStatsMapKey(final long uid) { - this.uid = uid; - } -} diff --git a/packages/ConnectivityT/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java b/packages/ConnectivityT/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java deleted file mode 100644 index e2253a2151b08..0000000000000 --- a/packages/ConnectivityT/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2011 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; - -import static com.android.server.NativeDaemonConnector.appendEscaped; -import static com.android.server.NativeDaemonConnector.makeCommand; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; - -import com.android.server.NativeDaemonConnector.SensitiveArg; - -/** - * Tests for {@link NativeDaemonConnector}. - */ -@MediumTest -public class NativeDaemonConnectorTest extends AndroidTestCase { - private static final String TAG = "NativeDaemonConnectorTest"; - - public void testArgumentNormal() throws Exception { - final StringBuilder builder = new StringBuilder(); - - builder.setLength(0); - appendEscaped(builder, ""); - assertEquals("", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo"); - assertEquals("foo", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo\"bar"); - assertEquals("foo\\\"bar", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo\\bar\\\"baz"); - assertEquals("foo\\\\bar\\\\\\\"baz", builder.toString()); - } - - public void testArgumentWithSpaces() throws Exception { - final StringBuilder builder = new StringBuilder(); - - builder.setLength(0); - appendEscaped(builder, "foo bar"); - assertEquals("\"foo bar\"", builder.toString()); - - builder.setLength(0); - appendEscaped(builder, "foo\"bar\\baz foo"); - assertEquals("\"foo\\\"bar\\\\baz foo\"", builder.toString()); - } - - public void testArgumentWithUtf() throws Exception { - final StringBuilder builder = new StringBuilder(); - - builder.setLength(0); - appendEscaped(builder, "caf\u00E9 c\u00F6ffee"); - assertEquals("\"caf\u00E9 c\u00F6ffee\"", builder.toString()); - } - - public void testSensitiveArgs() throws Exception { - final StringBuilder rawBuilder = new StringBuilder(); - final StringBuilder logBuilder = new StringBuilder(); - - rawBuilder.setLength(0); - logBuilder.setLength(0); - makeCommand(rawBuilder, logBuilder, 1, "foo", "bar", "baz"); - assertEquals("1 foo bar baz\0", rawBuilder.toString()); - assertEquals("1 foo bar baz", logBuilder.toString()); - - rawBuilder.setLength(0); - logBuilder.setLength(0); - makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("bar"), "baz"); - assertEquals("1 foo bar baz\0", rawBuilder.toString()); - assertEquals("1 foo [scrubbed] baz", logBuilder.toString()); - - rawBuilder.setLength(0); - logBuilder.setLength(0); - makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("foo bar"), "baz baz", - new SensitiveArg("wat")); - assertEquals("1 foo \"foo bar\" \"baz baz\" wat\0", rawBuilder.toString()); - assertEquals("1 foo [scrubbed] \"baz baz\" [scrubbed]", logBuilder.toString()); - } -} diff --git a/packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java b/packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java deleted file mode 100644 index ad0be5862c5d4..0000000000000 --- a/packages/ConnectivityT/tests/unit/java/com/android/server/net/IpConfigStoreTest.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.net; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -import android.net.InetAddresses; -import android.net.IpConfiguration; -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; -import android.net.LinkAddress; -import android.net.ProxyInfo; -import android.net.StaticIpConfiguration; -import android.util.ArrayMap; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Unit tests for {@link IpConfigStore} - */ -@RunWith(AndroidJUnit4.class) -public class IpConfigStoreTest { - private static final int KEY_CONFIG = 17; - private static final String IFACE_1 = "eth0"; - private static final String IFACE_2 = "eth1"; - private static final String IP_ADDR_1 = "192.168.1.10/24"; - private static final String IP_ADDR_2 = "192.168.1.20/24"; - private static final String DNS_IP_ADDR_1 = "1.2.3.4"; - private static final String DNS_IP_ADDR_2 = "5.6.7.8"; - - @Test - public void backwardCompatibility2to3() throws IOException { - ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); - DataOutputStream outputStream = new DataOutputStream(byteStream); - - final IpConfiguration expectedConfig = - newIpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); - - // Emulate writing to old format. - writeDhcpConfigV2(outputStream, KEY_CONFIG, expectedConfig); - - InputStream in = new ByteArrayInputStream(byteStream.toByteArray()); - ArrayMap configurations = IpConfigStore.readIpConfigurations(in); - - assertNotNull(configurations); - assertEquals(1, configurations.size()); - IpConfiguration actualConfig = configurations.get(String.valueOf(KEY_CONFIG)); - assertNotNull(actualConfig); - assertEquals(expectedConfig, actualConfig); - } - - @Test - public void staticIpMultiNetworks() throws Exception { - final ArrayList dnsServers = new ArrayList<>(); - dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1)); - dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2)); - final StaticIpConfiguration staticIpConfiguration1 = new StaticIpConfiguration.Builder() - .setIpAddress(new LinkAddress(IP_ADDR_1)) - .setDnsServers(dnsServers).build(); - final StaticIpConfiguration staticIpConfiguration2 = new StaticIpConfiguration.Builder() - .setIpAddress(new LinkAddress(IP_ADDR_2)) - .setDnsServers(dnsServers).build(); - - ProxyInfo proxyInfo = - ProxyInfo.buildDirectProxy("10.10.10.10", 88, Arrays.asList("host1", "host2")); - - IpConfiguration expectedConfig1 = newIpConfiguration(IpAssignment.STATIC, - ProxySettings.STATIC, staticIpConfiguration1, proxyInfo); - IpConfiguration expectedConfig2 = newIpConfiguration(IpAssignment.STATIC, - ProxySettings.STATIC, staticIpConfiguration2, proxyInfo); - - ArrayMap expectedNetworks = new ArrayMap<>(); - expectedNetworks.put(IFACE_1, expectedConfig1); - expectedNetworks.put(IFACE_2, expectedConfig2); - - MockedDelayedDiskWrite writer = new MockedDelayedDiskWrite(); - IpConfigStore store = new IpConfigStore(writer); - store.writeIpConfigurations("file/path/not/used/", expectedNetworks); - - InputStream in = new ByteArrayInputStream(writer.byteStream.toByteArray()); - ArrayMap actualNetworks = IpConfigStore.readIpConfigurations(in); - assertNotNull(actualNetworks); - assertEquals(2, actualNetworks.size()); - assertEquals(expectedNetworks.get(IFACE_1), actualNetworks.get(IFACE_1)); - assertEquals(expectedNetworks.get(IFACE_2), actualNetworks.get(IFACE_2)); - } - - private IpConfiguration newIpConfiguration(IpAssignment ipAssignment, - ProxySettings proxySettings, StaticIpConfiguration staticIpConfig, ProxyInfo info) { - final IpConfiguration config = new IpConfiguration(); - config.setIpAssignment(ipAssignment); - config.setProxySettings(proxySettings); - config.setStaticIpConfiguration(staticIpConfig); - config.setHttpProxy(info); - return config; - } - - // This is simplified snapshot of code that was used to store values in V2 format (key as int). - private static void writeDhcpConfigV2(DataOutputStream out, int configKey, - IpConfiguration config) throws IOException { - out.writeInt(2); // VERSION 2 - switch (config.getIpAssignment()) { - case DHCP: - out.writeUTF("ipAssignment"); - out.writeUTF(config.getIpAssignment().toString()); - break; - default: - fail("Not supported in test environment"); - } - - out.writeUTF("id"); - out.writeInt(configKey); - out.writeUTF("eos"); - } - - /** Synchronously writes into given byte steam */ - private static class MockedDelayedDiskWrite extends DelayedDiskWrite { - final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream(); - - @Override - public void write(String filePath, Writer w) { - DataOutputStream outputStream = new DataOutputStream(mByteStream); - - try { - w.onWriteCalled(outputStream); - } catch (IOException e) { - fail(); - } - } - } -}