From 8ff316034ad4e96a27a6a6273c99332666990fa6 Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Wed, 28 Aug 2019 13:01:05 -0700 Subject: [PATCH 01/49] Add missing nullability annotations. To prepare for enabling MissingNullability Metalava check this CL works on adding missing nullability issues that metalava flags if we tell it to flag new things since API 29. This is not a complete CL, mostly addresses public api and toString/equals for @SystemApi Exempt-From-Owner-Approval: Large scale nullability clean up Bug: 124515653 Test: make -j checkapi Change-Id: I109260842cfc25f06e40694997fcbb4afa02c867 --- core/java/android/net/IpSecManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 83813da80c..45d0c7313f 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -861,6 +861,7 @@ public final class IpSecManager { return mResourceId; } + @NonNull @Override public String toString() { return new StringBuilder() From 817cc44c62857d82fe0642f0ddf59b1a7568b87f Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Mon, 4 Nov 2019 11:16:45 +0000 Subject: [PATCH 02/49] Add @UnsupportedAppUsage to test apis that are known to be used by apps. go/testapi-enforcement Bug: 133832325 Test: m Change-Id: Ifc8db120640a1554dcbf1722e61e09c7ddc65dd6 Merged-In: Ifc8db120640a1554dcbf1722e61e09c7ddc65dd6 --- core/java/android/app/usage/NetworkStatsManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 8e40449fa5..6bade90182 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -146,6 +146,7 @@ public class NetworkStatsManager { } /** @hide */ + @UnsupportedAppUsage @TestApi public void setPollForce(boolean pollForce) { if (pollForce) { From 87f0b94f3b56dbac374aca068e1b38d443063d32 Mon Sep 17 00:00:00 2001 From: markchien Date: Mon, 30 Sep 2019 14:40:57 +0800 Subject: [PATCH 03/49] [Tether07] Migrate Tethering into module Now tethering would be run in dedicated service. TetheringManager is the interface used to communicate with TetheringService. The new call flow would be: ConnectivityManager -> ConnectivityService -> TetheringManager -> TetheringService. Note: the return value of #tether(), #untether() and #setUsbTethering() APIs would always be no error. Client can use #getLastTetherError() or #getTetheredIfaces or listen tether state change to check status of corresponding interface. Bug: 136040414 Bug: 144742179 Test: -build, flash, boot -atest TetheringTests -atest FrameworksNetTests Change-Id: I7e78c0e0a3e70f940a749ba2a39ece7c7ec5b9b3 --- .../core/java/com/android/server/net/NetworkStatsService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 08c94267e9..e473c96980 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -138,7 +138,6 @@ import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; import com.android.server.LocalServices; -import com.android.server.connectivity.Tethering; import java.io.File; import java.io.FileDescriptor; From a262cc1154f8d49521abddae8d8fa4c2ee91086e Mon Sep 17 00:00:00 2001 From: paulhu Date: Mon, 12 Aug 2019 16:25:11 +0800 Subject: [PATCH 04/49] Replace the permission of internal connectivity checks A number of connectivity checks that protect system-only methods check for CONNECTIVITY_INTERNAL, but CONNECTIVITY_INTERNAL is a signature|privileged permission. We should audit the permission checks, and convert checks that protect code that should not be called outside the system to a signature permission. So replace all CONNECTIVITY_INTERNAL to other proper permissions. Bug: 32963470 Test: atest FrameworksNetTests NetworkPolicyManagerServiceTest Change-Id: I8f2dd1cd0609056494eaf612d39820e273ae093f --- .../java/com/android/server/NsdService.java | 25 ++++++++----------- .../server/net/NetworkStatsService.java | 6 ++--- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 3efef017d2..b9b7bf73c1 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -16,19 +16,18 @@ package com.android.server; -import android.content.Context; import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager; import android.database.ContentObserver; +import android.net.NetworkStack; import android.net.Uri; -import android.net.nsd.NsdServiceInfo; import android.net.nsd.DnsSdTxtRecord; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; -import android.os.Binder; -import android.os.HandlerThread; +import android.net.nsd.NsdServiceInfo; import android.os.Handler; +import android.os.HandlerThread; import android.os.Message; import android.os.Messenger; import android.os.UserHandle; @@ -38,6 +37,12 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.AsyncChannel; +import com.android.internal.util.DumpUtils; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; @@ -45,13 +50,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.concurrent.CountDownLatch; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.AsyncChannel; -import com.android.internal.util.DumpUtils; -import com.android.internal.util.Protocol; -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; - /** * Network Service Discovery Service handles remote service discovery operation requests by * implementing the INsdManager interface. @@ -565,8 +563,7 @@ public class NsdService extends INsdManager.Stub { } public void setEnabled(boolean isEnabled) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL, - "NsdService"); + NetworkStack.checkNetworkStackPermission(mContext); mNsdSettings.putEnabledStatus(isEnabled); notifyEnabled(isEnabled); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index e473c96980..16424f2fef 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -17,7 +17,6 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; -import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; @@ -91,6 +90,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; import android.net.NetworkInfo; +import android.net.NetworkStack; import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; @@ -1020,8 +1020,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - // on background handler thread, and verified CONNECTIVITY_INTERNAL - // permission above. performPoll(FLAG_PERSIST_NETWORK); } }; @@ -1095,7 +1093,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void limitReached(String limitName, String iface) { // only someone like NMS should be calling us - mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + NetworkStack.checkNetworkStackPermission(mContext); if (LIMIT_GLOBAL_ALERT.equals(limitName)) { // kick off background poll to collect network stats unless there is already From f9f6d87ced895f094cfdcfdd681847a4d6a46c31 Mon Sep 17 00:00:00 2001 From: Jeffrey Huang Date: Thu, 5 Dec 2019 11:28:11 -0800 Subject: [PATCH 05/49] Rename writeToProto to be dumpDebug We want to eventually migrate some of these APIs to be @SystemApi for mainline modules. The #dumpDebug name is more appropriate than #writeToProto. Bug: 142279786 Test: Manual Change-Id: I60793e91cedf6b720d4ecef6a8484f4fed4ff30f --- core/java/android/net/NetworkIdentity.java | 2 +- core/java/android/net/NetworkStatsHistory.java | 14 +++++++------- .../com/android/server/net/NetworkIdentitySet.java | 4 ++-- .../android/server/net/NetworkStatsCollection.java | 6 +++--- .../android/server/net/NetworkStatsRecorder.java | 4 ++-- .../android/server/net/NetworkStatsService.java | 10 +++++----- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index febc730480..c1198aac27 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -114,7 +114,7 @@ public class NetworkIdentity implements Comparable { return builder.append("}").toString(); } - public void writeToProto(ProtoOutputStream proto, long tag) { + public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); proto.write(NetworkIdentityProto.TYPE, mType); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index f61260ee3e..d96d2ee481 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -684,7 +684,7 @@ public class NetworkStatsHistory implements Parcelable { } } - public void writeToProto(ProtoOutputStream proto, long tag) { + public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); @@ -693,11 +693,11 @@ public class NetworkStatsHistory implements Parcelable { final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]); - writeToProto(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); - writeToProto(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); - writeToProto(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); - writeToProto(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); - writeToProto(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, 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); } @@ -705,7 +705,7 @@ public class NetworkStatsHistory implements Parcelable { proto.end(start); } - private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) { + private static void dumpDebug(ProtoOutputStream proto, long tag, long[] array, int index) { if (array != null) { proto.write(tag, array[index]); } diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 68cd5e7aed..2326ad39fd 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -170,11 +170,11 @@ public class NetworkIdentitySet extends HashSet implements return ident.compareTo(anotherIdent); } - public void writeToProto(ProtoOutputStream proto, long tag) { + public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); for (NetworkIdentity ident : this) { - ident.writeToProto(proto, NetworkIdentitySetProto.IDENTITIES); + ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES); } proto.end(start); diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index ab525237db..05ab2ae87a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -687,7 +687,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } - public void writeToProto(ProtoOutputStream proto, long tag) { + public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); for (Key key : getSortedKeys()) { @@ -695,7 +695,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { // Key final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); - key.ident.writeToProto(proto, NetworkStatsCollectionKeyProto.IDENTITY); + key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY); proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); proto.write(NetworkStatsCollectionKeyProto.SET, key.set); proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); @@ -703,7 +703,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { // Value final NetworkStatsHistory history = mStats.get(key); - history.writeToProto(proto, NetworkStatsCollectionStatsProto.HISTORY); + history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY); proto.end(startStats); } diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index 06ec341d9e..6af962bbcc 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -470,12 +470,12 @@ public class NetworkStatsRecorder { } } - public void writeToProtoLocked(ProtoOutputStream proto, long tag) { + 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().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY); + getOrLoadCompleteLocked().dumpDebug(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY); proto.end(start); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 16424f2fef..673e8302a4 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1609,10 +1609,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces); dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces); - mDevRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); - mXtRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); - mUidRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); - mUidTagRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS); + 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(); } @@ -1623,7 +1623,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long start = proto.start(tag); proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); - ifaces.valueAt(i).writeToProto(proto, NetworkInterfaceProto.IDENTITIES); + ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES); proto.end(start); } From c6dee71164c81727475bc9ce8ac0da26e692513a Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Tue, 10 Dec 2019 17:47:51 +0000 Subject: [PATCH 06/49] Use new UnsupportedAppUsage annotation. Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library. Bug: 145132366 Test: m && diff unsupportedappusage_index.csv Change-Id: I8789f8499d4dca08580672e9e45ed9a7026dd686 --- core/java/android/app/usage/NetworkStatsManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 6bade90182..74129702b4 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -21,8 +21,8 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.usage.NetworkStats.Bucket; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.ConnectivityManager; import android.net.DataUsageRequest; From fb1d015c12218139a62517b44ff085419aa84ef5 Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Tue, 10 Dec 2019 17:47:53 +0000 Subject: [PATCH 07/49] Use new UnsupportedAppUsage annotation. Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library. Bug: 145132366 Test: m && diff unsupportedappusage_index.csv Change-Id: I534e3fd1305e2f4af076986770033478448a665c --- core/java/android/net/nsd/NsdServiceInfo.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 459b140980..0946499f16 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -17,13 +17,13 @@ package android.net.nsd; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; -import android.os.Parcelable; +import android.compat.annotation.UnsupportedAppUsage; 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 android.util.ArrayMap; import java.io.UnsupportedEncodingException; import java.net.InetAddress; From 634844fe4a6b4b31317510be852a52dba32920ef Mon Sep 17 00:00:00 2001 From: Daulet Zhanguzin Date: Mon, 30 Dec 2019 15:41:28 +0000 Subject: [PATCH 08/49] Replace com.android.internal.util.Preconditions.checkNotNull with java.util.Objects.requireNonNull Bug: 126528330 Test: Treehugger Change-Id: I42117ebfb640e3b0b133183e5e146860bed8471a --- core/java/android/app/usage/NetworkStatsManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 74129702b4..4346d9738e 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,8 +16,6 @@ package android.app.usage; -import static com.android.internal.util.Preconditions.checkNotNull; - import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.TestApi; @@ -42,6 +40,8 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import java.util.Objects; + /** * 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. @@ -418,7 +418,7 @@ public class NetworkStatsManager { /** @hide */ public void registerUsageCallback(NetworkTemplate template, int networkType, long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { - checkNotNull(callback, "UsageCallback cannot be null"); + Objects.requireNonNull(callback, "UsageCallback cannot be null"); final Looper looper; if (handler == null) { From c120601182de237c5029ae9a287f1c330fa5ec90 Mon Sep 17 00:00:00 2001 From: Daulet Zhanguzin Date: Fri, 3 Jan 2020 09:46:50 +0000 Subject: [PATCH 09/49] Replace com.android.internal.util.Preconditions.checkNotNull with java.util.Objects.requireNonNull Bug: 126528330 Test: Treehugger Exempt-From-Owner-Approval: Global refactoring. Change-Id: Idb1b6ba41af3b52f3376b1157259af3c30328c4e --- .../java/com/android/server/IpSecService.java | 19 +++++++++---------- .../android/server/NativeDaemonConnector.java | 3 ++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a629b3fbb8..c98762074b 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -25,8 +25,6 @@ import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; -import static com.android.internal.util.Preconditions.checkNotNull; - import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; @@ -76,6 +74,7 @@ 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 @@ -566,7 +565,7 @@ public class IpSecService extends IIpSecService.Stub { } void put(int key, RefcountedResource obj) { - checkNotNull(obj, "Null resources cannot be added"); + Objects.requireNonNull(obj, "Null resources cannot be added"); mArray.put(key, obj); } @@ -1101,7 +1100,7 @@ public class IpSecService extends IIpSecService.Stub { if (requestedSpi > 0 && requestedSpi < 256) { throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255."); } - checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); + Objects.requireNonNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); int callingUid = Binder.getCallingUid(); UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); @@ -1218,7 +1217,7 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException( "Specified port number must be a valid non-reserved UDP port"); } - checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); + Objects.requireNonNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); int callingUid = Binder.getCallingUid(); UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); @@ -1278,8 +1277,8 @@ public class IpSecService extends IIpSecService.Stub { String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder, String callingPackage) { enforceTunnelFeatureAndPermissions(callingPackage); - checkNotNull(binder, "Null Binder passed to createTunnelInterface"); - checkNotNull(underlyingNetwork, "No underlying network was specified"); + Objects.requireNonNull(binder, "Null Binder passed to createTunnelInterface"); + Objects.requireNonNull(underlyingNetwork, "No underlying network was specified"); checkInetAddress(localAddr); checkInetAddress(remoteAddr); @@ -1556,7 +1555,7 @@ public class IpSecService extends IIpSecService.Stub { "IPsec Tunnel Mode requires PackageManager.FEATURE_IPSEC_TUNNELS"); } - checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels"); + Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels"); switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) { case AppOpsManager.MODE_DEFAULT: mContext.enforceCallingOrSelfPermission( @@ -1625,12 +1624,12 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized IpSecTransformResponse createTransform( IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException { - checkNotNull(c); + Objects.requireNonNull(c); if (c.getMode() == IpSecTransform.MODE_TUNNEL) { enforceTunnelFeatureAndPermissions(callingPackage); } checkIpSecConfig(c); - checkNotNull(binder, "Null Binder passed to createTransform"); + Objects.requireNonNull(binder, "Null Binder passed to createTransform"); final int resourceId = mNextResourceId++; UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index ad02aad6e4..eac767f735 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -46,6 +46,7 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.LinkedList; +import java.util.Objects; /** * Generic connector class for interfacing with a native daemon which uses the @@ -126,7 +127,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public void setWarnIfHeld(Object warnIfHeld) { Preconditions.checkState(mWarnIfHeld == null); - mWarnIfHeld = Preconditions.checkNotNull(warnIfHeld); + mWarnIfHeld = Objects.requireNonNull(warnIfHeld); } @Override From 86716b78605747a029c38f13d7f52f32fa067bbf Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Tue, 10 Dec 2019 17:47:52 +0000 Subject: [PATCH 10/49] Use new UnsupportedAppUsage annotation. Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library. Bug: 145132366 Test: m && diff unsupportedappusage_index.csv Change-Id: I0c336de56bc4a041dc97ff9b7927f62f0b44b457 --- core/java/android/net/EthernetManager.java | 2 +- core/java/android/net/NetworkStats.java | 2 +- core/java/android/net/NetworkStatsHistory.java | 2 +- core/java/android/net/NetworkTemplate.java | 2 +- core/java/android/net/TrafficStats.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 72565024d3..fd015b4fe5 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,7 +17,7 @@ package android.net; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; import android.os.Message; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 6c7aa1379f..45bf4d2e13 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -19,7 +19,7 @@ package android.net; import static android.os.Process.CLAT_UID; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index d96d2ee481..6d46c205b2 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -30,7 +30,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 87c7118c0e..5e6c47a47a 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,7 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.removeDoubleQuotes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.BackupUtils; diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index bf4884aa96..162d6e27bd 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -20,10 +20,10 @@ import android.annotation.NonNull; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; 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.Build; From 1970749b5747eeb54a267aa12e894ad29b209e0e Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 6 Jan 2020 20:22:17 +0800 Subject: [PATCH 11/49] Move DnsSdTxtRecord to net common static library DnsSdTxtRecord is moved to frameworks/libs/net for mainline support. Also change the import path using this class. Bug: 139268426 Bug: 135998869 Test: atest FrameworksNetTests ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: I6118b313ce668707d598aa2eab9baee2f7622dbc --- services/core/java/com/android/server/NsdService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index b9b7bf73c1..4a1820a8e5 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -22,10 +22,10 @@ import android.content.Intent; import android.database.ContentObserver; import android.net.NetworkStack; import android.net.Uri; -import android.net.nsd.DnsSdTxtRecord; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; +import android.net.util.nsd.DnsSdTxtRecord; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; From 1d48d5e90d1f63c06d85328d5d2ccb37f0389afe Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 24 Jan 2020 19:29:17 +0900 Subject: [PATCH 12/49] Support putting one Ethernet interface in server mode. requestTetheredInterface can be used to put an interface in server mode, which will persist until release() is called on the returned request, or until the requesting process dies. Test: Enabled ethernet tethering with change on top Bug: 130840861 Change-Id: Id96d581acb3fa4e52ca62dd94ec257f56bd3a1ce --- core/java/android/net/EthernetManager.java | 78 ++++++++++++++++++- core/java/android/net/IEthernetManager.aidl | 3 + .../net/ITetheredInterfaceCallback.aidl | 23 ++++++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 core/java/android/net/ITetheredInterfaceCallback.aidl diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index fd015b4fe5..95000f5744 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.NonNull; import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -24,6 +25,7 @@ import android.os.Message; import android.os.RemoteException; import java.util.ArrayList; +import java.util.Objects; /** * A class representing the IP configuration of the Ethernet network. @@ -37,7 +39,7 @@ public class EthernetManager { private final Context mContext; private final IEthernetManager mService; - private final Handler mHandler = new Handler() { + private final Handler mHandler = new Handler(ConnectivityThread.getInstanceLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == MSG_AVAILABILITY_CHANGED) { @@ -180,4 +182,78 @@ public class EthernetManager { } } } + + /** + * 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. + */ + @NonNull + public TetheredInterfaceRequest requestTetheredInterface( + @NonNull TetheredInterfaceCallback callback) { + Objects.requireNonNull(callback, "Callback must be non-null"); + final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() { + @Override + public void onAvailable(String iface) { + callback.onAvailable(iface); + } + + @Override + public void onUnavailable() { + callback.onUnavailable(); + } + }; + + try { + mService.requestTetheredInterface(cbInternal); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return new TetheredInterfaceRequest(mService, cbInternal); + } } diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index 94960b51d3..ccc6e35209 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; +import android.net.ITetheredInterfaceCallback; /** * Interface that answers queries about, and allows changing @@ -32,4 +33,6 @@ interface IEthernetManager boolean isAvailable(String iface); void addListener(in IEthernetServiceListener listener); void removeListener(in IEthernetServiceListener listener); + void requestTetheredInterface(in ITetheredInterfaceCallback callback); + void releaseTetheredInterface(in ITetheredInterfaceCallback callback); } diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl new file mode 100644 index 0000000000..e3d075988c --- /dev/null +++ b/core/java/android/net/ITetheredInterfaceCallback.aidl @@ -0,0 +1,23 @@ +/* + * 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 */ +interface ITetheredInterfaceCallback { + void onAvailable(in String iface); + void onUnavailable(); +} \ No newline at end of file From c5c664b88db3d132a27f0467a70c8e1df67b96d0 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 24 Jan 2020 22:57:09 +0900 Subject: [PATCH 13/49] Add support for Ethernet tethering Ethernet tethering can be started via startTethering(TETHERING_ETHERNET). Test: flashed, enabled ethernet tethering, verified internet access on downstream. Bug: 130840861 Change-Id: I34842acd94b972e440c3622f7617df10c18acf65 --- core/java/android/net/EthernetManager.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 95000f5744..a3899b705c 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,7 +17,9 @@ package android.net; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; @@ -32,6 +34,8 @@ import java.util.Objects; * * @hide */ +@SystemApi +@TestApi @SystemService(Context.ETHERNET_SERVICE) public class EthernetManager { private static final String TAG = "EthernetManager"; @@ -62,12 +66,14 @@ public class EthernetManager { /** * A listener interface to receive notification on changes in Ethernet. + * @hide */ public interface Listener { /** * Called when Ethernet port's availability is changed. * @param iface Ethernet interface name * @param isAvailable {@code true} if Ethernet port exists. + * @hide */ @UnsupportedAppUsage void onAvailabilityChanged(String iface, boolean isAvailable); @@ -78,6 +84,7 @@ public class EthernetManager { * 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) { mContext = context; @@ -87,6 +94,7 @@ public class EthernetManager { /** * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. + * @hide */ @UnsupportedAppUsage public IpConfiguration getConfiguration(String iface) { @@ -99,6 +107,7 @@ public class EthernetManager { /** * Set Ethernet configuration. + * @hide */ @UnsupportedAppUsage public void setConfiguration(String iface, IpConfiguration config) { @@ -111,6 +120,7 @@ public class EthernetManager { /** * Indicates whether the system currently has one or more Ethernet interfaces. + * @hide */ @UnsupportedAppUsage public boolean isAvailable() { @@ -121,6 +131,7 @@ public class EthernetManager { * Indicates whether the system has given interface. * * @param iface Ethernet interface name + * @hide */ @UnsupportedAppUsage public boolean isAvailable(String iface) { @@ -135,6 +146,7 @@ public class EthernetManager { * Adds a listener. * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. + * @hide */ @UnsupportedAppUsage public void addListener(Listener listener) { @@ -153,6 +165,7 @@ public class EthernetManager { /** * Returns an array of available Ethernet interface names. + * @hide */ @UnsupportedAppUsage public String[] getAvailableInterfaces() { @@ -167,6 +180,7 @@ public class EthernetManager { * Removes a listener. * @param listener A {@link Listener} to remove. * @throws IllegalArgumentException If the listener is null. + * @hide */ @UnsupportedAppUsage public void removeListener(Listener listener) { From 7092cf164f5499b3a2a94cd3aedc9b2b2d94b93a Mon Sep 17 00:00:00 2001 From: David Su Date: Mon, 27 Jan 2020 13:27:50 -0800 Subject: [PATCH 14/49] Networking: Rename removeDoubleQuotes to sanitizeSsid Bug: 145745815 Test: compiles Change-Id: Iaa6f0d65cab556c24b0a9010427de8e6a02836c1 --- core/java/android/net/NetworkTemplate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 5e6c47a47a..5498f74ba2 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -32,7 +32,7 @@ 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 static android.net.wifi.WifiInfo.removeDoubleQuotes; +import static android.net.wifi.WifiInfo.sanitizeSsid; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -401,7 +401,7 @@ public class NetworkTemplate implements Parcelable { switch (ident.mType) { case TYPE_WIFI: return Objects.equals( - removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId)); + sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId)); default: return false; } From 9ee6603153ed91a5b03dd87943e0b7c4b5c0771f Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 12 Nov 2019 22:31:51 -0800 Subject: [PATCH 15/49] Implement Ikev2VpnRunner This change adds the implementation for IKEv2/IPsec VPNs. Bug: 144246767 Test: Manually tested Change-Id: I5ccec756cec49ccf57ccc4d5ad800eeb5d595a76 --- core/java/android/net/IpSecManager.java | 2 +- .../java/com/android/server/IpSecService.java | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 09ec6c35fc..d83715c692 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -51,7 +51,7 @@ import java.net.Socket; * *

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 a VPN should use {@link VpnService}. + * to create an IPsec VPN should use {@link VpnManager} and {@link Ikev2VpnProfile}. * * @see RFC 4301, Security Architecture for the * Internet Protocol diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index c98762074b..9540f43364 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1556,16 +1556,16 @@ public class IpSecService extends IIpSecService.Stub { } Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels"); - switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) { - case AppOpsManager.MODE_DEFAULT: - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); - break; - case AppOpsManager.MODE_ALLOWED: - return; - default: - throw new SecurityException("Request to ignore AppOps for non-legacy API"); + + // 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( From 87aa2869fe15a346ba2e02e328833e6fababa9fc Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Fri, 28 Feb 2020 03:42:44 +0000 Subject: [PATCH 16/49] Fix crash and duplicated ethernet tethering request This change fix two things: 1. Handle ethernet callback in internal thread to avoid crash. IpServer should be created from tethering thread, otherwise mIpNeighborMonitor of IpServer would throw IllegalStateException("start() called from off-thread") 2. Ethernet tethering request may be duplicated if multiple startTethering is called but no stopTethering Bug: 130840861 Bug: 148824036 Test: ON/OFF ethernet tehtering manually atest TetheringTests Change-Id: Ibd3ea6bc6751bd65647ff381f9b0124bc3395c09 Merged-In: I7c5127e96d80d077735010d2e62c7227805ccb10 Merged-In: Ibd3ea6bc6751bd65647ff381f9b0124bc3395c09 (cherry picked from commit 72702b979654234c18045f04270040056a74cf90) --- core/java/android/net/EthernetManager.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index a3899b705c..139f5bebcd 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -28,6 +28,7 @@ import android.os.RemoteException; import java.util.ArrayList; import java.util.Objects; +import java.util.concurrent.Executor; /** * A class representing the IP configuration of the Ethernet network. @@ -248,18 +249,19 @@ public class EthernetManager { * @param callback A callback to be called once the request has been fulfilled. */ @NonNull - public TetheredInterfaceRequest requestTetheredInterface( - @NonNull TetheredInterfaceCallback callback) { + 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) { - callback.onAvailable(iface); + executor.execute(() -> callback.onAvailable(iface)); } @Override public void onUnavailable() { - callback.onUnavailable(); + executor.execute(() -> callback.onUnavailable()); } }; From c0565de11ff07d737079f39b604afc381c759368 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Wed, 4 Mar 2020 13:36:11 +0000 Subject: [PATCH 17/49] Merge NetworkStatsService handler changes. ===== Remove the need of accessing handler in NSS unit test Currently, to wait for handler becomes idle, specific message is used and the test would wait for condition variable to be open when the message is processed. However, this is already done in the HandlerUtils. Thus, there is no need to post such message manually in the handler. Test: atest FrameworksNetTests Bug: 150664039 Change-Id: Iab32b2dbab01634ca159dcb90fc9f929d1fed1a2 ===== Remove setHandler in NetworkStatsService Currently, internal handler is set by setHandler after constructing NSS object. This was introduced in ag/866187 to access the handler in the unit test. However, the design put NSS in a bad situation where all classes that need handler or executor could not be final and need to be dynamically allocated in order to get a valid handler. Thus, since the usage of handler is removed in previous patch, this change eliminate setHandler by initializing the handler in the constructor. Test: atest FrameworksNetTests Bug: 150664039 Change-Id: I794a24d00b0ca9fdc78091e7b9ab7307e0f034b7 ===== Bug: 150664039 Change-Id: If256ed4437ddcbcc72a6f766cff2f4cc512ee3f7 Merged-In: If256ed4437ddcbcc72a6f766cff2f4cc512ee3f7 (cherry picked from commit 2a6439d7e2a3926e10a0b9a4dc730b1a022d8138) --- .../server/net/NetworkStatsService.java | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index ee5a4fe248..4af31b0369 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -306,9 +306,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); - /** Must be set in factory by calling #setHandler. */ - private Handler mHandler; - private Handler.Callback mHandlerCallback; + @NonNull + private final Handler mHandler; private volatile boolean mSystemReady; private long mPersistThreshold = 2 * MB_IN_BYTES; @@ -324,6 +323,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final static int DUMP_STATS_SESSION_COUNT = 20; + @NonNull + private final Dependencies mDeps; + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -339,9 +341,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Clock.systemUTC()); } - private static final class NetworkStatsHandler extends Handler { - NetworkStatsHandler(Looper looper, Handler.Callback callback) { - super(looper, callback); + 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_PERFORM_POLL_REGISTER_ALERT: { + performPoll(FLAG_PERSIST_NETWORK); + registerGlobalAlert(); + break; + } + } } } @@ -355,14 +372,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class), new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(), - new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir()); + new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), + new Dependencies()); service.registerLocalService(); - HandlerThread handlerThread = new HandlerThread(TAG); - Handler.Callback callback = new HandlerCallback(service); - handlerThread.start(); - Handler handler = new NetworkStatsHandler(handlerThread.getLooper(), callback); - service.setHandler(handler, callback); return service; } @@ -373,7 +386,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, TelephonyManager teleManager, NetworkStatsSettings settings, NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, - File baseDir) { + File baseDir, @NonNull Dependencies deps) { mContext = Objects.requireNonNull(context, "missing Context"); mNetworkManager = Objects.requireNonNull(networkManager, "missing INetworkManagementService"); @@ -387,6 +400,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir"); mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir"); mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists(); + mDeps = Objects.requireNonNull(deps, "missing Dependencies"); + + final HandlerThread handlerThread = mDeps.makeHandlerThread(); + handlerThread.start(); + mHandler = new NetworkStatsHandler(handlerThread.getLooper()); + } + + /** + * 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); + } } private void registerLocalService() { @@ -394,12 +427,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { new NetworkStatsManagerInternalImpl()); } - @VisibleForTesting - void setHandler(Handler handler, Handler.Callback callback) { - mHandler = handler; - mHandlerCallback = callback; - } - public void systemReady() { synchronized (mStatsLock) { mSystemReady = true; @@ -1920,33 +1947,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } - @VisibleForTesting - static class HandlerCallback implements Handler.Callback { - private final NetworkStatsService mService; - - HandlerCallback(NetworkStatsService service) { - this.mService = service; - } - - @Override - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_PERFORM_POLL: { - mService.performPoll(FLAG_PERSIST_ALL); - return true; - } - case MSG_PERFORM_POLL_REGISTER_ALERT: { - mService.performPoll(FLAG_PERSIST_NETWORK); - mService.registerGlobalAlert(); - return true; - } - default: { - return false; - } - } - } - } - private void assertSystemReady() { if (!mSystemReady) { throw new IllegalStateException("System not ready"); From 3bc71e0d898bae5ec49c72ef7ae39036bba6f2b2 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Mon, 9 Mar 2020 08:40:23 +0000 Subject: [PATCH 18/49] Add missing RequiresPermission to EthernetManager The method requires NETWORK_STACK or MAINLINE_NETWORK_STACK permissions, but the annotation was missing. Test: m Fixes: 150877670 Merged-In: I2af74cbcfa642f05f5e7bf85b2a8e8c38595f6ca (cherry picked from commit e45d3ff849695977cb063cc59550c505b220bd6c) Change-Id: Ia215b74df99ae60be2e380917be68a272d658ef4 --- core/java/android/net/EthernetManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 139f5bebcd..83b5f63576 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -248,6 +249,10 @@ public class EthernetManager { * 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) { From e953a50e6b586b1974233115e9e8a7b98b7cf6a5 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Thu, 12 Mar 2020 09:46:43 +0000 Subject: [PATCH 19/49] Add permission check functions to NetworkStatsService This is shameless copied from ConnectivityService and plan to be used in follow-up change. For long term perspective we should have a permission util that contains those util in one place. Test: m -j Change-Id: If70e6e831c0386b604d0151cc0650f68457b6e5f Merged-In: If70e6e831c0386b604d0151cc0650f68457b6e5f Merged-In: I837545b54f36c8f21c878cbb1fd028ff23be6cb8 Bug: 149652079 (cherry picked from commit 4da7af7e7e4a0d3360cd41e98e4d6fa731d21515) --- .../server/net/NetworkStatsService.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4af31b0369..cb3da918f4 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -23,6 +23,7 @@ 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.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStack.checkNetworkStackPermission; @@ -1793,6 +1794,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + // TODO: It is copied from ConnectivitySerivce, 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 From 050c7de0935a8db2ae8b3b595b71022d1dd34913 Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 16 Mar 2020 15:00:24 +0800 Subject: [PATCH 20/49] Fix typo in aosp/1242602 Test: m -j Bug: 149652079 Change-Id: Ie023c8371785fc239c54eacbf056141c2e9e3444 Merged-In: Ie023c8371785fc239c54eacbf056141c2e9e3444 (cherry picked from aosp/1259461) --- .../core/java/com/android/server/net/NetworkStatsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index cb3da918f4..45047048cc 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1794,7 +1794,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - // TODO: It is copied from ConnectivitySerivce, consider refactor these check permission + // 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) { From f62907d9ca02350c508c588b6a2fec7f13188398 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Thu, 12 Mar 2020 09:46:48 +0000 Subject: [PATCH 21/49] [SP20] Check signature permission when accessing network stats provider Currently, registerNetworkStatsProvider requires the UPDATE_DEVICE_STATS permission. This is a privileged permission so it can be granted to preinstalled apps. Thus, apps like GmsCore, or preinstalled apps will be able to update network stats. This change checks for a new permission that would only allow signature apps to declare that. Also check MAINLINE_NETWORK_STACK permission to allow NetworkStack process to use it. Test: adb shell dumpsys netstats Test: atest FrameworksNetTests Bug: 149652079 Change-Id: Iaecbf10a7610461bd52e315659006c7332c416e6 Merged-In: Iaecbf10a7610461bd52e315659006c7332c416e6 Merged-In: Idfebd0a1988c3dcfd812d87e30f6a2034d6fbf6b (cherry picked from commit e9e8d8f9ff096c1723eba1d74b17bb7cade7f23b) --- core/java/android/app/usage/NetworkStatsManager.java | 5 ++++- .../java/com/android/server/net/NetworkStatsService.java | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 5b98188300..7d13f050a7 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -29,6 +29,7 @@ import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.INetworkStatsService; import android.net.NetworkIdentity; +import android.net.NetworkStack; import android.net.NetworkTemplate; import android.net.netstats.provider.AbstractNetworkStatsProvider; import android.net.netstats.provider.NetworkStatsProviderCallback; @@ -540,7 +541,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) @NonNull public NetworkStatsProviderCallback registerNetworkStatsProvider( @NonNull String tag, @NonNull AbstractNetworkStatsProvider provider) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 45047048cc..a6c2c827fa 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -17,6 +17,7 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; +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.content.Intent.ACTION_SHUTDOWN; @@ -1828,7 +1829,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( @NonNull String tag, @NonNull INetworkStatsProvider provider) { - mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + enforceAnyPermissionOf(NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); Objects.requireNonNull(provider, "provider is null"); Objects.requireNonNull(tag, "tag is null"); try { From 27d58bfd962ec47e181f1d967193b14cadaff7e5 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 6 Mar 2020 14:50:48 +0800 Subject: [PATCH 22/49] [SP21] Address comments for API council review about aosp/1172143 Test: atest FrameworksNetTests ImsPhoneCallTrackerTest Test: atest TetheringTests NetworkStackTests Test: m doc-comment-check-docs Fix: 148552904 Change-Id: I141393f229e772d2eb9f7c156849e379bd71b845 Merged-In: I141393f229e772d2eb9f7c156849e379bd71b845 (cherry picked from aosp/1253717) --- .../app/usage/NetworkStatsManager.java | 48 +++-- .../provider/INetworkStatsProvider.aidl | 6 +- .../INetworkStatsProviderCallback.aidl | 6 +- .../provider/NetworkStatsProvider.java | 195 ++++++++++++++++++ .../server/net/NetworkStatsService.java | 23 +-- 5 files changed, 245 insertions(+), 33 deletions(-) create mode 100644 core/java/android/net/netstats/provider/NetworkStatsProvider.java diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 7d13f050a7..d6e77624a9 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -31,9 +31,8 @@ import android.net.INetworkStatsService; import android.net.NetworkIdentity; import android.net.NetworkStack; import android.net.NetworkTemplate; -import android.net.netstats.provider.AbstractNetworkStatsProvider; -import android.net.netstats.provider.NetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProviderWrapper; +import android.net.netstats.provider.INetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; import android.os.Handler; import android.os.Looper; @@ -528,34 +527,53 @@ public class NetworkStatsManager { /** * Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics - * to the system. To unregister, invoke {@link NetworkStatsProviderCallback#unregister()}. + * 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. + * 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 AbstractNetworkStatsProvider} that needs to be + * @param provider the subclass of {@link NetworkStatsProvider} that needs to be * registered to the system. - * @return a {@link NetworkStatsProviderCallback}, which can be used to report events to the - * system or unregister the provider. * @hide */ @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.NETWORK_STATS_PROVIDER, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) - @NonNull public NetworkStatsProviderCallback registerNetworkStatsProvider( + @NonNull public void registerNetworkStatsProvider( @NonNull String tag, - @NonNull AbstractNetworkStatsProvider provider) { + @NonNull NetworkStatsProvider provider) { try { - final NetworkStatsProviderWrapper wrapper = new NetworkStatsProviderWrapper(provider); - return new NetworkStatsProviderCallback( - mService.registerNetworkStatsProvider(tag, wrapper)); + 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(); } - // Unreachable code, but compiler doesn't know about it. - return null; } private static NetworkTemplate createTemplate(int networkType, String subscriberId) { diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl index 55b3d4edb1..4078b24921 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -22,7 +22,7 @@ package android.net.netstats.provider; * @hide */ oneway interface INetworkStatsProvider { - void requestStatsUpdate(int token); - void setLimit(String iface, long quotaBytes); - void setAlert(long quotaBytes); + void onRequestStatsUpdate(int token); + void onSetLimit(String iface, long quotaBytes); + void onSetAlert(long quotaBytes); } diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl index 3ea9318f10..bd336dd348 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -24,8 +24,8 @@ import android.net.NetworkStats; * @hide */ oneway interface INetworkStatsProviderCallback { - void onStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); - void onAlertReached(); - void onLimitReached(); + void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); + void notifyAlertReached(); + void notifyLimitReached(); void unregister(); } diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java new file mode 100644 index 0000000000..7639d2244c --- /dev/null +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -0,0 +1,195 @@ +/* + * 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} and {@link #onSetAlert} 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 onSetLimit(String iface, long quotaBytes) { + NetworkStatsProvider.this.onSetLimit(iface, quotaBytes); + } + + @Override + public void onSetAlert(long quotaBytes) { + NetworkStatsProvider.this.onSetAlert(quotaBytes); + } + }; + + // 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 quota set by {@code onSetLimit} 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 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/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index a6c2c827fa..46e865c7e8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -103,7 +103,7 @@ import android.net.NetworkTemplate; import android.net.TrafficStats; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProvider; import android.os.BestClock; import android.os.Binder; import android.os.DropBoxManager; @@ -558,7 +558,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (RemoteException e) { // ignored; service lives in system_server } - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setAlert(mGlobalAlertBytes)); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetAlert(mGlobalAlertBytes)); } @Override @@ -1376,7 +1376,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount(); mStatsProviderSem.drainPermits(); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.requestStatsUpdate(0 /* unused */)); + invokeForAllStatsProviderCallbacks( + (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); try { mStatsProviderSem.tryAcquire(registeredCallbackCount, MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS); @@ -1551,7 +1552,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setLimit(iface, quota)); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); } } @@ -1820,12 +1821,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * * @param tag a human readable identifier of the custom network stats provider. * @param provider the {@link INetworkStatsProvider} binder corresponding to the - * {@link android.net.netstats.provider.AbstractNetworkStatsProvider} to be - * registered. + * {@link NetworkStatsProvider} to be registered. * - * @return a binder interface of - * {@link android.net.netstats.provider.NetworkStatsProviderCallback}, which can be - * used to report events to the system. + * @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) { @@ -1931,7 +1930,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void onStatsUpdated(int token, @Nullable NetworkStats ifaceStats, + 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. @@ -1943,12 +1942,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void onAlertReached() throws RemoteException { + public void notifyAlertReached() throws RemoteException { mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */); } @Override - public void onLimitReached() { + public void notifyLimitReached() { Log.d(TAG, mTag + ": onLimitReached"); LocalServices.getService(NetworkPolicyManagerInternal.class) .onStatsProviderLimitReached(mTag); From ca952de92d7982bb9fcf1ad04477130c28475c75 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 13 Mar 2020 16:12:35 +0800 Subject: [PATCH 23/49] [SP23] Address misc API review comment about NetworkStats This change add several javadoc for NetworkStats and its Entry class. Also remove IFACE_ALL constant accordlingly. Test: atest FrameworkNetTests Test: m doc-comment-check-docs Bug: 148895143 Change-Id: Id1b8f41be79f847ad73197ff0e18258b6ee8a730 Merged-In: Id1b8f41be79f847ad73197ff0e18258b6ee8a730 (cherry picked from aosp/1256351) --- core/java/android/net/NetworkStats.java | 45 ++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 2f536ffd8c..10f7dbfc57 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,7 +21,6 @@ import static android.os.Process.CLAT_UID; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -58,9 +57,12 @@ import java.util.function.Predicate; public final class NetworkStats implements Parcelable { private static final String TAG = "NetworkStats"; - /** {@link #iface} value when interface details unavailable. */ - @SuppressLint("CompileTimeConstant") + /** + * {@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. @@ -248,7 +250,13 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage private long[] operations; - /** @hide */ + /** + * 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 */ @@ -319,6 +327,35 @@ public final class NetworkStats implements Parcelable { 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}. Should be one of the following + * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}. + * @param tag tag of this {@link Entry}. + * @param metered metered state of this {@link Entry}. Should be one of the following + * values: {link #METERED_YES}, {link #METERED_NO}. + * @param roaming roaming state of this {@link Entry}. Should be one of the following + * values: {link #ROAMING_YES}, {link #ROAMING_NO}. + * @param defaultNetwork default network status of this {@link Entry}. Should be one + * of the following values: {link #DEFAULT_NETWORK_YES}, + * {link #DEFAULT_NETWORK_NO}. + * @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) { From 02a6340ca0cc5838c1e5469e5391b9273284a5e6 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 13 Mar 2020 19:04:17 +0800 Subject: [PATCH 24/49] [SP24] Rename functions that add Entry unconditionally Currently, in NetworkStats, there are many methods to manipulate the records. However, some methods are similar and ambiguous, such as addEntry, addValues, setValues, addIfaceValues, combineValues and combineAllValues. Thus, properly grouping and renaming methods are necessary. In this change, for methods that add one record unconditionally, name them insertEntry. setIfaceValues -> insertEntry addEntry -> insertEntry Test: atest FrameworksNetTests ImsPhoneCallTrackerTest TetheringTests Test: m doc-comment-check-docs Bug: 148895143 Change-Id: I801ddc49e283a254b9586700c9b597c0adb0d459 Merged-In: I801ddc49e283a254b9586700c9b597c0adb0d459 (cherry picked from aosp/1256352) --- core/java/android/net/NetworkStats.java | 24 +++++++++---------- .../server/net/NetworkStatsFactory.java | 6 ++--- .../server/net/NetworkStatsService.java | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 10f7dbfc57..0fc74b0894 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -503,7 +503,7 @@ public final class NetworkStats implements Parcelable { NetworkStats.Entry entry = null; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - clone.addEntry(entry); + clone.insertEntry(entry); } return clone; } @@ -530,26 +530,26 @@ public final class NetworkStats implements Parcelable { /** @hide */ @VisibleForTesting - public NetworkStats addIfaceValues( + public NetworkStats insertEntry( String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { - return addEntry( + return insertEntry( iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); } /** @hide */ @VisibleForTesting - public NetworkStats addEntry(String iface, int uid, int set, int tag, long rxBytes, + public NetworkStats insertEntry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - return addEntry(new Entry( + return insertEntry(new Entry( iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } /** @hide */ @VisibleForTesting - public NetworkStats addEntry(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 addEntry(new Entry( + 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)); } @@ -559,7 +559,7 @@ public final class NetworkStats implements Parcelable { * object can be recycled across multiple calls. * @hide */ - public NetworkStats addEntry(Entry entry) { + public NetworkStats insertEntry(Entry entry) { if (size >= capacity) { final int newLength = Math.max(size, 10) * 3 / 2; iface = Arrays.copyOf(iface, newLength); @@ -702,7 +702,7 @@ public final class NetworkStats implements Parcelable { entry.roaming, entry.defaultNetwork); if (i == -1) { // only create new entry when positive contribution - addEntry(entry); + insertEntry(entry); } else { rxBytes[i] += entry.rxBytes; rxPackets[i] += entry.rxPackets; @@ -1040,7 +1040,7 @@ public final class NetworkStats implements Parcelable { entry.operations = Math.max(entry.operations, 0); } - result.addEntry(entry); + result.insertEntry(entry); } return result; diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 22b01bee6c..75ffe35674 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -229,7 +229,7 @@ public class NetworkStatsFactory { entry.txPackets += reader.nextLong(); } - stats.addEntry(entry); + stats.insertEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -279,7 +279,7 @@ public class NetworkStatsFactory { entry.txBytes = reader.nextLong(); entry.txPackets = reader.nextLong(); - stats.addEntry(entry); + stats.insertEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -439,7 +439,7 @@ public class NetworkStatsFactory { if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface)) && (limitUid == UID_ALL || limitUid == entry.uid) && (limitTag == TAG_ALL || limitTag == entry.tag)) { - stats.addEntry(entry); + stats.insertEntry(entry); } reader.finishLine(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 46e865c7e8..10136b3b8b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -759,7 +759,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, + 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; From 544bc807a4641b540e9f432986ce209cb3250954 Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 16 Mar 2020 13:27:28 +0800 Subject: [PATCH 25/49] [SP25] Rename functions that add Entry conditionally Currently, in NetworkStats, there are many methods to manipulate the records. However, some methods are similar and ambiguous, such as addEntry, addValues, setValues, addIfaceValues, combineValues and combineAllValues. Thus, properly grouping and renaming methods are necessary. In this change, for methods that add one record conditionally, name them addEntry. addValues -> addEntry Test: atest FrameworksNetTests ImsPhoneCallTrackerTest TetheringTests Fix: 148895143 Change-Id: I9495a198cf247e6c79100f7ac1edcea370b071de --- core/java/android/net/NetworkStats.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 0fc74b0894..9c1fb41ecc 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -721,7 +721,7 @@ public final class NetworkStats implements Parcelable { * @param entry the {@link Entry} to add. * @return a new constructed {@link NetworkStats} object that contains the result. */ - public @NonNull NetworkStats addValues(@NonNull Entry entry) { + public @NonNull NetworkStats addEntry(@NonNull Entry entry) { return this.clone().combineValues(entry); } From 825f0828ac3671ab5d18c0a854468bed3f8c3a34 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 12 Dec 2019 19:42:59 +0800 Subject: [PATCH 26/49] [SM02] Support record mobile network stats by collapsed rat type Previously network stats could be recorded by different rat type. However, the feature was disabled by ag/173504 since rat type frequently flapping between HSPA+ and UMTS. Given that this feature might be useful for collecting metrics, re-implement it based on current architecture and reduce the overhead introduced by frequently flapping by: 1. only react when rat type changes between 2G/3G/4G/5G. 2. reduce the number of records by only recording a subset of rat type that represented for a given network class. 3. enforce 1 second rate limit if flapping too much. Note that the feature is still disabled but will be enabled in follow-up patches. Test: manual test Bug: 129082217 Change-Id: Ic6b2f10f2c8b082820e0662eb9cee70d70d28cd6 Merged-In: Ic6b2f10f2c8b082820e0662eb9cee70d70d28cd6 (cherry picked from commit 15ab452e7e3f00289fbedbdb86c512ad560dda7e) --- core/java/android/net/NetworkIdentity.java | 15 ++-- core/java/android/net/NetworkTemplate.java | 40 +++++++++ .../server/net/NetworkStatsService.java | 89 ++++++++++++++++++- 3 files changed, 134 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index c1198aac27..b67ad519b4 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -25,6 +25,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.service.NetworkIdentityProto; +import android.telephony.Annotation.NetworkType; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -42,11 +43,8 @@ public class NetworkIdentity implements Comparable { /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. - * - * @deprecated we no longer offer to collect statistics on a per-subtype - * basis; this is always disabled. */ - @Deprecated + // TODO: make this flag configurable through settings. See http://b/146415925 public static final boolean COMBINE_SUBTYPE_ENABLED = true; public static final int SUBTYPE_COMBINED = -1; @@ -187,13 +185,14 @@ public class NetworkIdentity implements Comparable { } /** - * Build a {@link NetworkIdentity} from the given {@link NetworkState}, - * assuming that any mobile networks are using the current IMSI. + * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType}, + * assuming that any mobile networks are using the current IMSI. The subType if applicable, + * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or + * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. */ public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state, - boolean defaultNetwork) { + boolean defaultNetwork, @NetworkType int subType) { final int type = state.networkInfo.getType(); - final int subType = state.networkInfo.getSubtype(); String subscriberId = null; String networkId = null; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 5498f74ba2..6080d16b9d 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -37,6 +37,7 @@ import static android.net.wifi.WifiInfo.sanitizeSsid; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.TelephonyManager; import android.util.BackupUtils; import android.util.Log; @@ -394,6 +395,45 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Get a Radio Access Technology(RAT) type that is representative of a group of RAT types. + * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}. + * + * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. + */ + // TODO: 1. Consider move this to TelephonyManager if used by other modules. + // 2. Consider make this configurable. + // 3. Use TelephonyManager APIs when available. + 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; + default: + return TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + } + /** * Check if matches Wi-Fi network template. */ diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 10136b3b8b..7c4624d25c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,6 +27,8 @@ import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; +import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; +import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; @@ -45,6 +47,7 @@ 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.NetworkTemplate.getCollapsedRatType; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; @@ -64,6 +67,9 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; +import static android.telephony.PhoneStateListener.LISTEN_NONE; +import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE; +import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; 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; @@ -109,6 +115,7 @@ import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.INetworkManagementService; @@ -125,6 +132,8 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; import android.telephony.SubscriptionPlan; import android.telephony.TelephonyManager; import android.text.format.DateUtils; @@ -157,6 +166,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -173,6 +183,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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_UPDATE_IFACES = 3; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -280,6 +291,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; + /** Last states of all networks sent from ConnectivityService. */ + @GuardedBy("mStatsLock") + @Nullable + private NetworkState[] mLastNetworkStates = null; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -355,6 +371,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performPoll(FLAG_PERSIST_ALL); break; } + case MSG_UPDATE_IFACES: { + // If no cached states, ignore. + if (mLastNetworkStates == null) break; + updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface); + break; + } case MSG_PERFORM_POLL_REGISTER_ALERT: { performPoll(FLAG_PERSIST_NETWORK); registerGlobalAlert(); @@ -407,6 +429,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HandlerThread handlerThread = mDeps.makeHandlerThread(); handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); + mPhoneListener = new NetworkTypeListener(new HandlerExecutor(mHandler)); } /** @@ -486,6 +509,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); + // TODO: listen to changes from all subscriptions. + // watch for networkType changes + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); + } + registerGlobalAlert(); } @@ -506,6 +535,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_NONE); + } + final long currentTime = mClock.millis(); // persist any pending stats @@ -1156,6 +1189,38 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + /** + * Receiver that watches for {@link TelephonyManager} changes, such as + * transitioning between Radio Access Technology(RAT) types. + */ + @NonNull + private final NetworkTypeListener mPhoneListener; + + class NetworkTypeListener extends PhoneStateListener { + private volatile int mLastCollapsedRatType = NETWORK_TYPE_UNKNOWN; + + NetworkTypeListener(@NonNull Executor executor) { + super(executor); + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState ss) { + final int networkType = ss.getDataNetworkType(); + final int collapsedRatType = getCollapsedRatType(networkType); + if (collapsedRatType == mLastCollapsedRatType) return; + + if (LOGV) { + Log.d(TAG, "subtype changed for mobile: " + + mLastCollapsedRatType + " -> " + collapsedRatType); + } + // Protect service from frequently updating. Remove pending messages if any. + mHandler.removeMessages(MSG_UPDATE_IFACES); + mLastCollapsedRatType = collapsedRatType; + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); + } + } + private void updateIfaces( Network[] defaultNetworks, NetworkState[] networkStates, @@ -1177,7 +1242,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { + private void updateIfacesLocked(@Nullable Network[] defaultNetworks, + @NonNull NetworkState[] states) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1197,13 +1263,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mDefaultNetworks = defaultNetworks; } + mLastNetworkStates = states; + final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); + final int subType = getSubTypeForState(state); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, - isDefault); + isDefault, subType); // Traffic occurring on the base interface is always counted for // both total usage and UID details. @@ -1264,6 +1333,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]); } + /** + * If combine subtype is not enabled. For networks with {@code TRANSPORT_CELLULAR}, get + * subType that obtained through {@link PhoneStateListener}. Otherwise, return 0 given that + * other networks with different transport types do not actually fill this value. + */ + private int getSubTypeForState(@NonNull NetworkState state) { + if (COMBINE_SUBTYPE_ENABLED) return SUBTYPE_COMBINED; + + if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + return 0; + } + + // TODO: return different subType for different subscriptions. + return mPhoneListener.mLastCollapsedRatType; + } + private static NetworkIdentitySet findOrCreateNetworkIdentitySet( ArrayMap map, K key) { NetworkIdentitySet ident = map.get(key); From 00d94e3335653c307d8e2099dacbb7ed7387917e Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 20 Dec 2019 16:35:34 +0800 Subject: [PATCH 27/49] [SM04] Support fetching data with NetworkTemplate with subType Add a NetworkTemplate build function that allows user to specify subType. NetworkStats corresponding to the same group would be retrieved. Test: atest FrameworksNetTests Bug: 129082217 Change-Id: Ie2d229be0b6bd239f799989c070475c73a096d71 Merged-In: Ie2d229be0b6bd239f799989c070475c73a096d71 (cherry picked from commit e19045cc4ab1f2cd133ce5dc0c3a38e3275417ad) --- core/java/android/net/NetworkTemplate.java | 60 +++++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 6080d16b9d..cb9463a59d 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,10 +34,13 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.sanitizeSsid; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.Annotation.NetworkType; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.BackupUtils; import android.util.Log; @@ -74,6 +77,14 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; + /** + * 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. + * + * @hide + */ + public static final int NETWORK_TYPE_ALL = -1; + private static boolean isKnownMatchRule(final int rule) { switch (rule) { case MATCH_MOBILE: @@ -118,7 +129,22 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks, + * Template to match cellular networks with the given IMSI and {@code ratType}. + * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. + * See {@code TelephonyManager.NETWORK_TYPE_*}. + */ + public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, + @NetworkType int ratType) { + if (TextUtils.isEmpty(subscriberId)) { + return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + } + return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + } + + /** + * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ @UnsupportedAppUsage @@ -127,7 +153,7 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks, + * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, * regardless of SSID. */ @UnsupportedAppUsage @@ -193,6 +219,7 @@ public class NetworkTemplate implements Parcelable { private final int mMetered; private final int mRoaming; private final int mDefaultNetwork; + private final int mSubType; @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { @@ -202,11 +229,11 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL); + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL); } public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String networkId, int metered, int roaming, int defaultNetwork) { + String networkId, int metered, int roaming, int defaultNetwork, int subType) { mMatchRule = matchRule; mSubscriberId = subscriberId; mMatchSubscriberIds = matchSubscriberIds; @@ -214,6 +241,7 @@ public class NetworkTemplate implements Parcelable { mMetered = metered; mRoaming = roaming; mDefaultNetwork = defaultNetwork; + mSubType = subType; if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule @@ -229,6 +257,7 @@ public class NetworkTemplate implements Parcelable { mMetered = in.readInt(); mRoaming = in.readInt(); mDefaultNetwork = in.readInt(); + mSubType = in.readInt(); } @Override @@ -240,6 +269,7 @@ public class NetworkTemplate implements Parcelable { dest.writeInt(mMetered); dest.writeInt(mRoaming); dest.writeInt(mDefaultNetwork); + dest.writeInt(mSubType); } @Override @@ -272,13 +302,16 @@ public class NetworkTemplate implements Parcelable { builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( mDefaultNetwork)); } + if (mSubType != NETWORK_TYPE_ALL) { + builder.append(", subType=").append(mSubType); + } return builder.toString(); } @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork); + mDefaultNetwork, mSubType); } @Override @@ -290,7 +323,8 @@ public class NetworkTemplate implements Parcelable { && Objects.equals(mNetworkId, other.mNetworkId) && mMetered == other.mMetered && mRoaming == other.mRoaming - && mDefaultNetwork == other.mDefaultNetwork; + && mDefaultNetwork == other.mDefaultNetwork + && mSubType == other.mSubType; } return false; } @@ -377,6 +411,11 @@ public class NetworkTemplate implements Parcelable { || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); } + private boolean matchesCollapsedRatType(NetworkIdentity ident) { + return mSubType == NETWORK_TYPE_ALL + || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); + } + public boolean matchesSubscriberId(String subscriberId) { return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); } @@ -389,9 +428,13 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { + // Only metered mobile network would be matched regardless of metered filter. + // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. + // TODO: Respect metered filter and remove mMetered condition. return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) && !ArrayUtils.isEmpty(mMatchSubscriberIds) - && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) + && matchesCollapsedRatType(ident); } } @@ -461,7 +504,8 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered); + return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) + && matchesCollapsedRatType(ident); } } From dddf7d0a9a8eb5fc8bb09434832f42df4458a816 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 31 Dec 2019 13:40:15 +0800 Subject: [PATCH 28/49] [SM05] Enable record mobile network stats by collapsed rat type Switch on the recording in device side. Metrics will be collected in follow-up patches which can be independently enabled/disabled. This change also fix the fail in NetworkStatsCollectionTest which caused by enabling this feature, where the rounding problem happened when records are distributed into smaller buckets and categorized into more NetworkIdentity. Test: atest FrameworksNetTests Bug: 129082217 Change-Id: If330e85330a4ff713dd420c98d42fa741eabd90a Merged-In: If330e85330a4ff713dd420c98d42fa741eabd90a (cherry picked from commit 2d4fa2c0fae8c2d79a25093d9f732a33c2f91dd4) --- core/java/android/net/NetworkIdentity.java | 2 +- .../core/java/com/android/server/net/NetworkStatsService.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index b67ad519b4..2cf3531d2f 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -45,7 +45,7 @@ public class NetworkIdentity implements Comparable { * {@link #SUBTYPE_COMBINED}. */ // TODO: make this flag configurable through settings. See http://b/146415925 - public static final boolean COMBINE_SUBTYPE_ENABLED = true; + public static final boolean COMBINE_SUBTYPE_ENABLED = false; public static final int SUBTYPE_COMBINED = -1; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 7c4624d25c..ff4407aa12 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1209,7 +1209,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return; - if (LOGV) { + if (LOGD) { Log.d(TAG, "subtype changed for mobile: " + mLastCollapsedRatType + " -> " + collapsedRatType); } @@ -1217,7 +1217,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandler.removeMessages(MSG_UPDATE_IFACES); mLastCollapsedRatType = collapsedRatType; mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); + mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); } } From 1e30781571dc50e18c5d34b346910b617aee7071 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 2 Jan 2020 19:35:59 +0800 Subject: [PATCH 29/49] [SM07] Make combine subtype configurable from Settings Note that enabling/disabling would not take effect until device reboot. This will be addressed in follow-up patch. Test: 1. atest NetworkStatsServieTest SettingsBackupTest 2. adb shell settings put global netstats_combine_subtype_enabled 1|0 Bug: 146415925 Change-Id: Ic94da540afa479ed18f1b6fbda4ae3216c37476b Merged-In: Ic94da540afa479ed18f1b6fbda4ae3216c37476b (cherry picked from commit c4f77ac90bf2e48a655ad19b162fe74a23bf3fb0) --- core/java/android/net/NetworkIdentity.java | 11 +-- .../server/net/NetworkStatsService.java | 69 ++++++++++++------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 2cf3531d2f..0948a4da1a 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -40,13 +40,6 @@ import java.util.Objects; public class NetworkIdentity implements Comparable { private static final String TAG = "NetworkIdentity"; - /** - * When enabled, combine all {@link #mSubType} together under - * {@link #SUBTYPE_COMBINED}. - */ - // TODO: make this flag configurable through settings. See http://b/146415925 - public static final boolean COMBINE_SUBTYPE_ENABLED = false; - public static final int SUBTYPE_COMBINED = -1; final int mType; @@ -61,7 +54,7 @@ public class NetworkIdentity implements Comparable { int type, int subType, String subscriberId, String networkId, boolean roaming, boolean metered, boolean defaultNetwork) { mType = type; - mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; + mSubType = subType; mSubscriberId = subscriberId; mNetworkId = networkId; mRoaming = roaming; @@ -93,7 +86,7 @@ public class NetworkIdentity implements Comparable { final StringBuilder builder = new StringBuilder("{"); builder.append("type=").append(getNetworkTypeName(mType)); builder.append(", subType="); - if (COMBINE_SUBTYPE_ENABLED) { + if (mSubType == SUBTYPE_COMBINED) { builder.append("COMBINED"); } else { builder.append(mSubType); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index ff4407aa12..d8264b3625 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,7 +27,6 @@ import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; -import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -52,6 +51,7 @@ import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED; +import static android.provider.Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED; import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES; @@ -240,12 +240,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Settings that can be changed externally. */ public interface NetworkStatsSettings { - public long getPollInterval(); - public long getPollDelay(); - public boolean getSampleEnabled(); - public boolean getAugmentEnabled(); + long getPollInterval(); + long getPollDelay(); + boolean getSampleEnabled(); + boolean getAugmentEnabled(); + /** + * When enabled, all mobile data is reported under {@link NetworkIdentity#SUBTYPE_COMBINED}. + * When disabled, mobile data is broken down by a granular subtype representative of the + * actual subtype. {@see NetworkTemplate#getCollapsedRatType}. + * Enabling this decreases the level of detail but saves performance, disk space and + * amount of data logged. + */ + boolean getCombineSubtypeEnabled(); - public static class Config { + class Config { public final long bucketDuration; public final long rotateAgeMillis; public final long deleteAgeMillis; @@ -257,16 +265,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public Config getDevConfig(); - public Config getXtConfig(); - public Config getUidConfig(); - public Config getUidTagConfig(); + Config getDevConfig(); + Config getXtConfig(); + Config getUidConfig(); + Config getUidTagConfig(); - public long getGlobalAlertBytes(long def); - public long getDevPersistBytes(long def); - public long getXtPersistBytes(long def); - public long getUidPersistBytes(long def); - public long getUidTagPersistBytes(long def); + 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(); @@ -509,9 +517,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); - // TODO: listen to changes from all subscriptions. + // TODO: 1. listen to changes from all subscriptions. + // 2. listen to settings changed to support dynamically enable/disable. // watch for networkType changes - if (!COMBINE_SUBTYPE_ENABLED) { + if (!mSettings.getCombineSubtypeEnabled()) { mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); } @@ -535,9 +544,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); - if (!COMBINE_SUBTYPE_ENABLED) { - mTeleManager.listen(mPhoneListener, LISTEN_NONE); - } + mTeleManager.listen(mPhoneListener, LISTEN_NONE); final long currentTime = mClock.millis(); @@ -1265,12 +1272,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mLastNetworkStates = states; + final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); - final int subType = getSubTypeForState(state); + final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED + : getSubTypeForState(state); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, isDefault, subType); @@ -1334,13 +1343,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * If combine subtype is not enabled. For networks with {@code TRANSPORT_CELLULAR}, get - * subType that obtained through {@link PhoneStateListener}. Otherwise, return 0 given that - * other networks with different transport types do not actually fill this value. + * For networks with {@code TRANSPORT_CELLULAR}, get subType 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 getSubTypeForState(@NonNull NetworkState state) { - if (COMBINE_SUBTYPE_ENABLED) return SUBTYPE_COMBINED; - if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return 0; } @@ -1702,6 +1709,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } + pw.println("Configs:"); + pw.increaseIndent(); + pw.printPair(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled()); + pw.println(); + pw.decreaseIndent(); + pw.println("Active interfaces:"); pw.increaseIndent(); for (int i = 0; i < mActiveIfaces.size(); i++) { @@ -2130,6 +2143,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalBoolean(NETSTATS_AUGMENT_ENABLED, true); } @Override + public boolean getCombineSubtypeEnabled() { + return getGlobalBoolean(NETSTATS_COMBINE_SUBTYPE_ENABLED, false); + } + @Override public Config getDevConfig() { return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), From 8723291cee7516bf82d2806d961c6aa12fc5c6d0 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 19 Mar 2020 11:46:55 +0000 Subject: [PATCH 30/49] Make Ethernet interfaces more testable. This CL adds a setIncludeTestInterfaces method to EthernetManager that, when called, causes the Ethernet service to recognize and manage test interfaces created by TestNetworkManager. Bug: 150644681 Test: Tested by EthernetTetheringTest in same topic Change-Id: I86eef7a93267f800dbfc8eafd307effa76a344ca Merged-In: I86eef7a93267f800dbfc8eafd307effa76a344ca (cherry picked from commit 3410fb0aa92bbd4f9d7dc031e89f6f528ff34245) --- core/java/android/net/EthernetManager.java | 15 +++++++++++++++ core/java/android/net/IEthernetManager.aidl | 1 + 2 files changed, 16 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 83b5f63576..d975017f9c 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -199,6 +199,21 @@ public class EthernetManager { } } + /** + * 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 + */ + @TestApi + public void setIncludeTestInterfaces(boolean include) { + try { + mService.setIncludeTestInterfaces(include); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * A request for a tethered interface. */ diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index ccc6e35209..e058e5a70c 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -33,6 +33,7 @@ interface IEthernetManager 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); } From fd266f85b62684c93e8f9cd1d5dea51db5e10ea9 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Wed, 25 Mar 2020 00:49:05 +0000 Subject: [PATCH 31/49] Relax IPsec resource count restrictions. IPsec resource counts were selected to be conservative, due to unknowns about device capabilities. Since then, it appears that we no longer need such stringent quotas, and this can be relaxed. Bug: 152368091 Test: FrameworksNetTest passing Change-Id: Id53d14e5698e5fcc410868424176b00350c7ae79 Merged-In: Id53d14e5698e5fcc410868424176b00350c7ae79 (cherry picked from commit 224699fc0b485dd75e6157a88f66a53d64e5a6fd) --- .../core/java/com/android/server/IpSecService.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 9540f43364..599485b11c 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -359,10 +359,14 @@ public class IpSecService extends IIpSecService.Stub { @VisibleForTesting static final class UserRecord { /* Maximum number of each type of resource that a single UID may possess */ - public static final int MAX_NUM_TUNNEL_INTERFACES = 2; - public static final int MAX_NUM_ENCAP_SOCKETS = 2; - public static final int MAX_NUM_TRANSFORMS = 4; - public static final int MAX_NUM_SPIS = 8; + + // 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 From 3fafd684c5f222ea52e6ccca099bc0f5a61286d9 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 25 Mar 2020 05:50:51 +0000 Subject: [PATCH 32/49] Automatically set IPsec tunnel interface as up This change makes IPsec tunnel interfaces automatically get brought up once they are created. Originally this was considered to be an additional safety check, as they would not be start routing traffic until explicitly brought up. However, in the intervening time, the NetworkManagementController now requires the NETWORK_STACK permission to set an interface as up. Additionally, that call is a hidden API, and thus not usable for use cases such as IWLAN. Bug: 149348618 Test: FrameworksNetTests, CtsNetTestCases passing. Change-Id: I55b63a748463a388e1e2991d2d5d6b3023545e60 Merged-In: I55b63a748463a388e1e2991d2d5d6b3023545e60 (cherry picked from commit 7c5704d177a903034ae1b6ae4800cc3b8457977a) --- .../java/com/android/server/IpSecService.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 599485b11c..905c489e1d 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -46,6 +46,7 @@ import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; +import android.os.INetworkManagementService; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -114,6 +115,9 @@ public class IpSecService extends IIpSecService.Stub { /* Binder context for this service */ private final Context mContext; + /* NetworkManager instance */ + private final INetworkManagementService mNetworkManager; + /** * 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 @@ -992,12 +996,13 @@ public class IpSecService extends IIpSecService.Stub { * * @param context Binder context for this service */ - private IpSecService(Context context) { - this(context, IpSecServiceConfiguration.GETSRVINSTANCE); + private IpSecService(Context context, INetworkManagementService networkManager) { + this(context, networkManager, IpSecServiceConfiguration.GETSRVINSTANCE); } - static IpSecService create(Context context) throws InterruptedException { - final IpSecService service = new IpSecService(context); + static IpSecService create(Context context, INetworkManagementService networkManager) + throws InterruptedException { + final IpSecService service = new IpSecService(context, networkManager); service.connectNativeNetdService(); return service; } @@ -1011,9 +1016,11 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService(Context context, IpSecServiceConfiguration config) { + public IpSecService(Context context, INetworkManagementService networkManager, + IpSecServiceConfiguration config) { this( context, + networkManager, config, (fd, uid) -> { try { @@ -1027,9 +1034,10 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService( - Context context, IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { + public IpSecService(Context context, INetworkManagementService networkManager, + IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { mContext = context; + mNetworkManager = Objects.requireNonNull(networkManager); mSrvConfig = config; mUidFdTagger = uidFdTagger; } @@ -1308,6 +1316,10 @@ public class IpSecService extends IIpSecService.Stub { final INetd netd = mSrvConfig.getNetdInstance(); netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); + Binder.withCleanCallingIdentity(() -> { + mNetworkManager.setInterfaceUp(intfName); + }); + for (int selAddrFamily : ADDRESS_FAMILIES) { // Always send down correct local/remote addresses for template. netd.ipSecAddSecurityPolicy( From eba72cd4ef5988461371af395de094da82b09446 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 11 Feb 2020 14:59:38 +0800 Subject: [PATCH 33/49] [SM06] Collect mobile NetworkStats metrics by collapsed rat type Test: adb shell cmd stats pull-source 10000~10003 adb shell dumpsys netstats --uid Bug: 129082217 Change-Id: I726e74f5c63a6ed456cb13ea259b58c7a33bec76 Merged-In: I726e74f5c63a6ed456cb13ea259b58c7a33bec76 (cherry picked from commit c82dfeb4225e1a8a17eedc969a90f921e0bf845c) --- core/java/android/net/NetworkTemplate.java | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index cb9463a59d..eba7ff3483 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,6 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.sanitizeSsid; +import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -52,6 +53,8 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -477,6 +480,32 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Return all supported collapsed RAT types that could be returned by + * {@link #getCollapsedRatType(int)}. + */ + @NonNull + public static final int[] getAllCollapsedRatTypes() { + final int[] ratTypes = TelephonyManager.getAllNetworkTypes(); + final HashSet collapsedRatTypes = new HashSet<>(); + for (final int ratType : ratTypes) { + collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); + } + // Ensure that unknown type is returned. + collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); + return toIntArray(collapsedRatTypes); + } + + @NonNull + private static int[] toIntArray(@NonNull Collection list) { + final int[] array = new int[list.size()]; + int i = 0; + for (final Integer item : list) { + array[i++] = item; + } + return array; + } + /** * Check if matches Wi-Fi network template. */ From d81034383d0f8708ae3e88a9b55462ff76193364 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 2 Apr 2020 18:36:24 +0000 Subject: [PATCH 34/49] [SP26.2] add a method in NetworkStats that removes empty entries In current design, entries with zeros are preserved after addition/subtraction. These entries are not very useful and lead to difficulty of verifying the result of addition/subtraction. However, change the behavior in the original NetworkStats is considered risky in current stage. Thus, this change provide a function that could remove these empty entries in tests. Test: atest FrameworksNetTests Bug: 152827872 Bug: 150644692 Change-Id: I40a76935d55712b8083ee1e17e137a8a4ef5e029 Merged-In: I40a76935d55712b8083ee1e17e137a8a4ef5e029 (cherry picked from commit 6c7bef3064dbe949b7b213036b8e70c125ddd343) --- core/java/android/net/NetworkStats.java | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9c1fb41ecc..b7fb280efd 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1195,18 +1195,24 @@ public final class NetworkStats implements Parcelable { /** * Remove all rows that match one of specified UIDs. + * This mutates the original structure in place. * @hide */ public void removeUids(int[] uids) { - int nextOutputEntry = 0; - for (int i = 0; i < size; i++) { - if (!ArrayUtils.contains(uids, uid[i])) { - maybeCopyEntry(nextOutputEntry, i); - nextOutputEntry++; - } - } + filter(e -> !ArrayUtils.contains(uids, e.uid)); + } - size = nextOutputEntry; + /** + * 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; } /** From 5d0d638f540ae558e3fbe55b1470af84c6e5673d Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 4 Mar 2020 12:48:50 +0800 Subject: [PATCH 35/49] [SM09] Add helper class to monitor RAT type change per sub In current design, Rat type change in NSS is only for default subscription. This is only correct for single sim project. However, it does not correct for multi-sim scenarios such as CBRS or DSDS, given that all data usage will be attributed to the Rat type of default sub. Thus, add a helper class to monitor subscription change event, and register/unregister dynamically for Rat type change for every subscription. Note that unit test of the helper class will be addressed in follow-up patch. Test: m -j Bug: 146415925 Change-Id: I0055f6b55c209a073ce997fc7a144477f9db7069 Merged-In: I0055f6b55c209a073ce997fc7a144477f9db7069 (cherry picked from commit 306de26c138ec135846f2a74a952464cf00dce54) --- .../net/NetworkStatsSubscriptionsMonitor.java | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java new file mode 100644 index 0000000000..0bdf3f22ee --- /dev/null +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -0,0 +1,211 @@ +/* + * 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.net.NetworkTemplate.getCollapsedRatType; + +import android.annotation.NonNull; +import android.content.Context; +import android.telephony.Annotation; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.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. + */ +// TODO (b/152176562): Write tests to verify subscription changes generate corresponding +// register/unregister calls. +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.net.NetworkTemplate#getCollapsedRatType(int). + */ + void onCollapsedRatTypeChanged(@NonNull String subscriberId, + @Annotation.NetworkType int collapsedRatType); + } + private final Delegate mDelegate; + + /** + * Receivers that watches for {@link ServiceState} 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); + + for (final int subId : newSubs) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> it.mSubId == subId); + if (match != null) continue; + + // Create listener for every newly added sub. Also store subscriberId into it to + // prevent binder call to telephony when querying RAT. + final String subscriberId = mTeleManager.getSubscriberId(subId); + if (TextUtils.isEmpty(subscriberId)) { + Log.wtf(NetworkStatsService.TAG, + "Empty subscriberId for newly added sub: " + subId); + } + final RatTypeListener listener = + new RatTypeListener(mExecutor, this, subId, subscriberId); + mRatListeners.add(listener); + + // Register listener to the telephony manager that associated with specific sub. + mTeleManager.createForSubscriptionId(subId) + .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); + } + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + // If the new list contains the subId of the listener, keeps it. + final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId); + if (match != null) continue; + + 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 RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> TextUtils.equals(subscriberId, it.mSubscriberId)); + return match != null ? match.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) + .listen(listener, PhoneStateListener.LISTEN_NONE); + 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 PhoneStateListener { + // 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 Executor executor, + @NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, + @NonNull String subscriberId) { + super(executor); + mSubId = subId; + mSubscriberId = subscriberId; + mMonitor = monitor; + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState ss) { + final int networkType = ss.getDataNetworkType(); + 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); + } + } +} From 7bab8e86df0e7086683d77d4a7e81e201e903a51 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 10 Apr 2020 13:54:43 -0600 Subject: [PATCH 36/49] Narrow access to getDataLayerSnapshotForUid(). This method is used in TrafficStats to obtain the snapshot for the calling UID, so narrow it to only return data for that specific case. We might be tempted to throw an exception or adjust the method signature, but apps are using the raw AIDL in the greylist, so we return them an empty NetworkStats if they ask about other UIDs. Bug: 119672472 Test: manual Change-Id: I3064630039f1d8473d6425dd663f17813a4ae3a1 --- .../core/java/com/android/server/net/NetworkStatsService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index d8264b3625..c3a1a883e5 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -16,7 +16,6 @@ package com.android.server.net; -import static android.Manifest.permission.ACCESS_NETWORK_STATE; 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; @@ -845,7 +844,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException { if (Binder.getCallingUid() != uid) { - mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG); + Log.w(TAG, "Snapshots only available for calling UID"); + return new NetworkStats(SystemClock.elapsedRealtime(), 0); } // TODO: switch to data layer stats once kernel exports From f0fcc339c333031276e1eeb2226572438e0a6bdd Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 4 Mar 2020 12:58:00 +0800 Subject: [PATCH 37/49] [SM10] Adopt helper class to monitor RAT type change per sub Test: atest NetworkStatsServiceTest Bug: 146415925 Change-Id: I45c3aa9046b316c8cd0943543d620a22e4afefd1 Merged-In: I45c3aa9046b316c8cd0943543d620a22e4afefd1 (cherry picked from commit 219faff07bdc58c14fe58fc525e86383db1f8167) --- .../server/net/NetworkStatsService.java | 86 ++++++++----------- 1 file changed, 37 insertions(+), 49 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index d8264b3625..f7d0d4ee16 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -46,7 +46,6 @@ 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.NetworkTemplate.getCollapsedRatType; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; @@ -67,9 +66,6 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; -import static android.telephony.PhoneStateListener.LISTEN_NONE; -import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE; -import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; 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; @@ -133,9 +129,7 @@ import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; import android.telephony.SubscriptionPlan; -import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -206,7 +200,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final NetworkStatsFactory mStatsFactory; private final AlarmManager mAlarmManager; private final Clock mClock; - private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; private final NetworkStatsObservers mStatsObservers; @@ -352,6 +345,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull private final Dependencies mDeps; + @NonNull + private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor; + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -401,8 +397,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, - wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class), + final NetworkStatsService service = new NetworkStatsService(context, networkManager, + alarmManager, wakeLock, getDefaultClock(), new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), new Dependencies()); @@ -416,16 +412,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @VisibleForTesting NetworkStatsService(Context context, INetworkManagementService networkManager, AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, - TelephonyManager teleManager, NetworkStatsSettings settings, - NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, - File baseDir, @NonNull Dependencies deps) { + NetworkStatsSettings settings, NetworkStatsFactory factory, + NetworkStatsObservers statsObservers, File systemDir, File baseDir, + @NonNull Dependencies deps) { mContext = Objects.requireNonNull(context, "missing Context"); mNetworkManager = Objects.requireNonNull(networkManager, - "missing INetworkManagementService"); + "missing INetworkManagementService"); mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager"); mClock = Objects.requireNonNull(clock, "missing Clock"); mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings"); - mTeleManager = Objects.requireNonNull(teleManager, "missing TelephonyManager"); mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock"); mStatsFactory = Objects.requireNonNull(factory, "missing factory"); mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers"); @@ -437,7 +432,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HandlerThread handlerThread = mDeps.makeHandlerThread(); handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); - mPhoneListener = new NetworkTypeListener(new HandlerExecutor(mHandler)); + mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, + new HandlerExecutor(mHandler), this); } /** @@ -453,6 +449,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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 forceUpdateIface. + return new NetworkStatsSubscriptionsMonitor(context, executor, (subscriberId, type) -> + service.handleOnCollapsedRatTypeChanged()); + } } private void registerLocalService() { @@ -517,11 +526,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); - // TODO: 1. listen to changes from all subscriptions. - // 2. listen to settings changed to support dynamically enable/disable. + // TODO: listen to settings changed to support dynamically enable/disable. // watch for networkType changes if (!mSettings.getCombineSubtypeEnabled()) { - mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); + mNetworkStatsSubscriptionsMonitor.start(); } registerGlobalAlert(); @@ -544,7 +552,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); - mTeleManager.listen(mPhoneListener, LISTEN_NONE); + if (!mSettings.getCombineSubtypeEnabled()) { + mNetworkStatsSubscriptionsMonitor.stop(); + } final long currentTime = mClock.millis(); @@ -1197,35 +1207,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { }; /** - * Receiver that watches for {@link TelephonyManager} changes, such as - * transitioning between Radio Access Technology(RAT) types. + * Handle collapsed RAT type changed event. */ - @NonNull - private final NetworkTypeListener mPhoneListener; - - class NetworkTypeListener extends PhoneStateListener { - private volatile int mLastCollapsedRatType = NETWORK_TYPE_UNKNOWN; - - NetworkTypeListener(@NonNull Executor executor) { - super(executor); - } - - @Override - public void onServiceStateChanged(@NonNull ServiceState ss) { - final int networkType = ss.getDataNetworkType(); - final int collapsedRatType = getCollapsedRatType(networkType); - if (collapsedRatType == mLastCollapsedRatType) return; - - if (LOGD) { - Log.d(TAG, "subtype changed for mobile: " - + mLastCollapsedRatType + " -> " + collapsedRatType); - } - // Protect service from frequently updating. Remove pending messages if any. - mHandler.removeMessages(MSG_UPDATE_IFACES); - mLastCollapsedRatType = collapsedRatType; - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); - } + @VisibleForTesting + public void handleOnCollapsedRatTypeChanged() { + // Protect service from frequently updating. Remove pending messages if any. + mHandler.removeMessages(MSG_UPDATE_IFACES); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); } private void updateIfaces( @@ -1352,8 +1341,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return 0; } - // TODO: return different subType for different subscriptions. - return mPhoneListener.mLastCollapsedRatType; + return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.subscriberId); } private static NetworkIdentitySet findOrCreateNetworkIdentitySet( From d80a6ed9e283d4e5a577e606c39685507584aeea Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Mon, 17 Jun 2019 16:22:28 -0700 Subject: [PATCH 38/49] Enforce permission check in getUidStats function The NetworkStatsService.getUidStats() currently doesn't have any permission check to make sure unpriviledged apps cannot read the stats of a different uid. It will protentially have security problem since apps with ACCESS_NETWORK_STATS permission can directly calling into NetworkStatsService and bypass the check in TrafficStats. Move the uid check from TrafficStats to NetworkStatsService to fix the problem. Bug: 129151407 Test: atest AppSecurityTests#testAppFailAccessPrivateData_full Test: atest AppSecurityTests#testAppFailAccessPrivateData_instant Test: atest android.app.usage.cts.NetworkUsageStatsTest Test: atest NetworkStatsBinderTest Change-Id: Iae85676cfe5f114da69ec278afc2c904bc907234 --- core/java/android/net/TrafficStats.java | 60 +++++-------------- .../server/net/NetworkStatsService.java | 5 ++ 2 files changed, 21 insertions(+), 44 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 8108cf08d5..e7bba69dbb 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -775,17 +775,10 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidTxBytes(int uid) { - // This isn't actually enforcing any security; it just returns the - // unsupported value. The real filtering is done at the kernel level. - final int callingUid = android.os.Process.myUid(); - if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - try { - return getStatsService().getUidStats(uid, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } else { - return UNSUPPORTED; + try { + return getStatsService().getUidStats(uid, TYPE_TX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -808,17 +801,10 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidRxBytes(int uid) { - // This isn't actually enforcing any security; it just returns the - // unsupported value. The real filtering is done at the kernel level. - final int callingUid = android.os.Process.myUid(); - if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - try { - return getStatsService().getUidStats(uid, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } else { - return UNSUPPORTED; + try { + return getStatsService().getUidStats(uid, TYPE_RX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -841,17 +827,10 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidTxPackets(int uid) { - // This isn't actually enforcing any security; it just returns the - // unsupported value. The real filtering is done at the kernel level. - final int callingUid = android.os.Process.myUid(); - if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - try { - return getStatsService().getUidStats(uid, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } else { - return UNSUPPORTED; + try { + return getStatsService().getUidStats(uid, TYPE_TX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -874,17 +853,10 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidRxPackets(int uid) { - // This isn't actually enforcing any security; it just returns the - // unsupported value. The real filtering is done at the kernel level. - final int callingUid = android.os.Process.myUid(); - if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - try { - return getStatsService().getUidStats(uid, TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } else { - return UNSUPPORTED; + try { + return getStatsService().getUidStats(uid, TYPE_RX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index d8264b3625..003e7fc837 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -49,6 +49,7 @@ import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.NetworkTemplate.getCollapsedRatType; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; +import static android.net.TrafficStats.UNSUPPORTED; import static android.os.Trace.TRACE_TAG_NETWORK; import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED; import static android.provider.Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED; @@ -1021,6 +1022,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @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, checkBpfStatsEnable()); } From abfadbefef5de05fcd7f47af341c96f49edeac9b Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 28 Apr 2020 22:15:56 +0800 Subject: [PATCH 39/49] Filter debug entries for each vpn NetworkStats calculation needs to filter out debug entries to prevent over counting. While NetworkStatsFactory migrates data usage over a VPN to the TUN network, NetworkStatsFactory does not filter out debug entries per vpn which will cause debug entries left and cause exception. Bug: 152678151 Test: atest com.android.server.net.NetworkStatsFactoryTest and verify no exception Change-Id: I3525edc385b07858b48c7add2d331c4b5a2e84ad Merged-In: I3525edc385b07858b48c7add2d331c4b5a2e84ad --- .../java/com/android/server/net/NetworkStatsFactory.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 75ffe35674..3dac106418 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -385,11 +385,10 @@ public class NetworkStatsFactory { // Migrate data usage over a VPN to the TUN network. for (VpnInfo info : vpnArray) { delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); + // Filter out debug entries as that may lead to over counting. + delta.filterDebugEntries(); } - // 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()); From 55119e823e068743ada99e63a53ae08a927cd92c Mon Sep 17 00:00:00 2001 From: Lucas Lin Date: Thu, 7 May 2020 10:12:30 +0000 Subject: [PATCH 40/49] Broadcast ACTION_NETWORK_STATS_UPDATED in NetworkStatsHandler There is a corner case which may cause the deadlock: When NetworkStatsService tried to broadcast the intent, NetworkStatsService was waiting for a lock which was hold by ActivityManagerService. In the same time, ActivityManagerService was waiting for ActiveService#startServiceInnerLocked() to get a lock which was hold by ConnectivityService. ConnectivityService was waiting for a lock which was hold by BatteryStatsImpl. BatteryStatsImpl was waiting for a lock which was hold by NetworkStatsService, and the lock was locked by NetworkStatsService when NetworkStatsService tried to broadcast the intent. To prevent deadlock when broadcasting the intent in performPollLocked(), move the intent broadcasting from performPollLocked() to NetworkStatsHandler. Bug: 150418178 Bug: 155155473 Test: 1. Create the second user and see if the device will do factory reset or not. 2. Factory reset manually and see if there is a deadlock. Change-Id: I80569cb4388beb3fd6cbf64a7885bccee8b1c53c Merged-In: Icf88d3e7a38562ab15187f6c71bc8fb0486d37c0 (cherry picked from commit 3f8ab0350450202910ea702799570c538e96d5cd) --- .../android/server/net/NetworkStatsService.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 1951fc071d..adf017633c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -178,6 +178,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // 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_UPDATE_IFACES = 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; @@ -386,6 +389,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { 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; + } } } } @@ -1513,10 +1523,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // finally, dispatch updated event to any listeners - 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); + mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED)); Trace.traceEnd(TRACE_TAG_NETWORK); } From 003c5c980765c9cc0078ff1d92f03a8b454abdd6 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 3 Oct 2019 11:09:00 -0700 Subject: [PATCH 41/49] Use TransformRecord to get SPI instead of SpiRecord IpSecService.applyTunnelModeTransform() currently does not take an SpiRecord instance, yet implicitly requires that the SpiRecord instance is still alive based on the stored SpiRecord resourceId in the TransformRecord's IpSecConfig. This check is unnecessary, as the SpiRecord has been subsumed into the TransformRecord, and the kernel resources are kept alive whether or not the SpiRecord is still held by the user. This allows users of the IpSecManager API to allocate short-lived SPIs during the creation of an IpSecTransform, without having to keep track of both of them (even though the SPI is no longer usable). The TransformRecord.getSpiRecord() call is already used in multiple other places in the same method. Bug: 142072071 Test: New tests added, passing. Change-Id: I1959f3080946267243564459ff4207647922566e Merged-In: I1959f3080946267243564459ff4207647922566e (cherry picked from commit 5258b1b82f39bf17e0751bcb94479464250aaec5) --- services/core/java/com/android/server/IpSecService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 905c489e1d..6402e07bdd 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1776,7 +1776,7 @@ public class IpSecService extends IIpSecService.Stub { socketRecord = userRecord.mEncapSocketRecords.getResourceOrThrow(c.getEncapSocketResourceId()); } - SpiRecord spiRecord = userRecord.mSpiRecords.getResourceOrThrow(c.getSpiResourceId()); + SpiRecord spiRecord = transformInfo.getSpiRecord(); int mark = (direction == IpSecManager.DIRECTION_OUT) @@ -1809,7 +1809,7 @@ public class IpSecService extends IIpSecService.Stub { // 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 = transformInfo.getSpiRecord().getSpi(); + spi = spiRecord.getSpi(); } // Always update the policy with the relevant XFRM_IF_ID From 1d4d01a8a866de2561fd98f1738aa36e09df7d52 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Tue, 12 May 2020 11:06:23 +0000 Subject: [PATCH 42/49] Use CopyOnWriteArrayList to store list of NetworkStatsProviderCb In NetworkStatsService, mStatsLock will be held when iterating through the provider list. This is to protect the list from concurrent broadcast that triggered by NetworkPolicyManagerService. This is not good since the binder call is oneway, it does not make sense to block every access to the providers. This change also remove unuse variable and reduce verbose log. Test: atest FrameworksNetTests TetheringTests Bug: 150418178 Change-Id: If74e9f2ea597a0d5ae4668c3358bc687f342bbb5 Merged-In: If74e9f2ea597a0d5ae4668c3358bc687f342bbb5 (cherry picked from commit 5d8f96c6967d5b1a42ba374521078e75a9e6f187) --- .../server/net/NetworkStatsService.java | 49 +++++++------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index adf017633c..dcbdfdf7a2 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -119,7 +119,6 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; -import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -160,6 +159,7 @@ 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; @@ -226,12 +226,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String PREFIX_UID = "uid"; private static final String PREFIX_UID_TAG = "uid_tag"; - /** - * Virtual network interface for video telephony. This is for VT data usage counting purpose. - */ - // TODO: Remove this after no one is using it. - public static final String VT_INTERFACE = NetworkStats.IFACE_VT; - /** * Settings that can be changed externally. */ @@ -304,8 +298,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { new DropBoxNonMonotonicObserver(); private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100; - private final RemoteCallbackList mStatsProviderCbList = - new RemoteCallbackList<>(); + 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); @@ -1466,10 +1460,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; // 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. + // 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.getRegisteredCallbackCount(); + final int registeredCallbackCount = mStatsProviderCbList.size(); mStatsProviderSem.drainPermits(); invokeForAllStatsProviderCallbacks( (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); @@ -1643,7 +1641,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { - Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); + if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); } } @@ -1934,7 +1932,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( tag, provider, mStatsProviderSem, mAlertObserver, mStatsProviderCbList); - mStatsProviderCbList.register(callback); + mStatsProviderCbList.add(callback); Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" + getCallingUid() + "/" + getCallingPid()); return callback; @@ -1958,20 +1956,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void invokeForAllStatsProviderCallbacks( @NonNull ThrowingConsumer task) { - synchronized (mStatsLock) { - final int length = mStatsProviderCbList.beginBroadcast(); + for (final NetworkStatsProviderCallbackImpl cb : mStatsProviderCbList) { try { - for (int i = 0; i < length; i++) { - final NetworkStatsProviderCallbackImpl cb = - mStatsProviderCbList.getBroadcastItem(i); - try { - task.accept(cb); - } catch (RemoteException e) { - Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); - } - } - } finally { - mStatsProviderCbList.finishBroadcast(); + task.accept(cb); + } catch (RemoteException e) { + Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); } } } @@ -1983,7 +1972,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull final INetworkStatsProvider mProvider; @NonNull private final Semaphore mSemaphore; @NonNull final INetworkManagementEventObserver mAlertObserver; - @NonNull final RemoteCallbackList mStatsProviderCbList; + @NonNull final CopyOnWriteArrayList mStatsProviderCbList; @NonNull private final Object mProviderStatsLock = new Object(); @@ -1997,7 +1986,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull String tag, @NonNull INetworkStatsProvider provider, @NonNull Semaphore semaphore, @NonNull INetworkManagementEventObserver alertObserver, - @NonNull RemoteCallbackList cbList) + @NonNull CopyOnWriteArrayList cbList) throws RemoteException { mTag = tag; mProvider = provider; @@ -2054,13 +2043,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void binderDied() { Log.d(TAG, mTag + ": binderDied"); - mStatsProviderCbList.unregister(this); + mStatsProviderCbList.remove(this); } @Override public void unregister() { Log.d(TAG, mTag + ": unregister"); - mStatsProviderCbList.unregister(this); + mStatsProviderCbList.remove(this); } } From d4ce044ad11b39cd1958ddce7dac0901528a6757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 May 2020 00:58:07 +0000 Subject: [PATCH 43/49] NetworkStatsService - xt_qtaguid non-ebpf - account stacked interface stats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: atest bpf_module_test clatd_test libbpf_android_test libnetdbpf_test netd_integration_test netd_unit_test netdutils_test Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: I297fcad0a83bd8c32c0fa6c6a77d83b42cd8c428 Merged-In: I297fcad0a83bd8c32c0fa6c6a77d83b42cd8c428 --- .../server/net/NetworkStatsService.java | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index dcbdfdf7a2..cf5a412321 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1311,21 +1311,39 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // 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 until they are translated. // - // Interface stats are more complicated. Packets subject to BPF offload - // never appear on the base interface and only appear on the stacked - // interface, so to ensure those packets increment interface stats, interface - // stats from stacked interfaces must be collected. + // 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. + // final List stackedLinks = state.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); if (stackedIface != null) { - if (mUseBpfTrafficStats) { - findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); - } + findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); if (isMobile) { mobileIfaces.add(stackedIface); From 5c9097c9e0a078b43b14b1b797c436523aaf7589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 24 Dec 2019 02:50:35 -0800 Subject: [PATCH 44/49] NetworkStats - no need for xt_qtaguid clat bw fixups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is due to the previous addition of the ip6tables raw PREROUTING drop rules for incoming ipv6 clat traffic pre-translation to ipv4. Since we no longer double account, we no longer need these fixups. Test: atest bpf_module_test clatd_test libbpf_android_test libnetdbpf_test netd_integration_test netd_unit_test netdutils_test Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: Ia171b7797cdc99367064d0649bf1293c71579941 Merged-In: Ia171b7797cdc99367064d0649bf1293c71579941 --- core/java/android/net/NetworkStats.java | 64 ++++++++++--------------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index b7fb280efd..3141320a16 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1047,22 +1047,22 @@ public final class NetworkStats implements Parcelable { } /** - * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. + * Calculate and apply adjustments to captured statistics for 464xlat traffic. * - *

This mutates both base and stacked traffic stats, to account respectively for - * double-counted traffic and IPv4/IPv6 header size difference. + *

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

For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 - * packet on the stacked interface, and once as translated to an IPv6 packet on the - * base interface. For correct stats accounting on the base interface, if using xt_qtaguid, - * every rx 464xlat packet needs to be subtracted from the root UID on the base interface - * (http://b/12249687, http:/b/33681750), and every tx 464xlat packet which was counted onto - * clat uid should be ignored. + *

UID stats, which are only accounted on the stacked interface, need to be increased + * by 20 bytes/packet to account for translation overhead. * - * As for eBPF, the per uid stats is collected by different hook, the rx packets on base - * interface will not be counted. Thus, the adjustment on root uid is not needed. However, the - * tx traffic counted in the same way xt_qtaguid does, so the traffic on clat uid still - * needs to be ignored. + *

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} @@ -1074,46 +1074,34 @@ public final class NetworkStats implements Parcelable { */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic, Map stackedIfaces, boolean useBpfStats) { - // Total 464xlat traffic to subtract from uid 0 on all base interfaces. - // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. - final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); - // For recycling Entry entry = null; - Entry adjust = new NetworkStats.Entry(IFACE_ALL, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); - for (int i = 0; i < stackedTraffic.size; i++) { entry = stackedTraffic.getValues(i, entry); - if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { - continue; - } - final String baseIface = stackedIfaces.get(entry.iface); - if (baseIface == null) { - continue; - } - // Subtract xt_qtaguid 464lat rx traffic seen for the root UID on the current base - // interface. As for eBPF, the per uid stats is collected by different hook, the rx - // packets on base interface will not be counted. - adjust.iface = baseIface; - if (!useBpfStats) { - adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets = -entry.rxPackets; - } - adjustments.combineValues(adjust); + 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); } - // Traffic on clat uid is v6 tx traffic that is already counted with app uid on the stacked - // v4 interface, so it needs to be removed to avoid double-counting. + // Theoretically there should be no traffic accounted to the clat daemon's uid: + // see ebpf program 'netd.c's early returns + // and iptables '-m owner --uid-owner clat -j RETURN' rules prior to accounting + // TODO: remove this - should definitely be safe once ebpf only. baseTraffic.removeUids(new int[] {CLAT_UID}); - baseTraffic.combineAllValues(adjustments); } /** From c7d0224c75e0be5382d04230bacbbd6683431d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 May 2020 01:06:28 -0700 Subject: [PATCH 45/49] NetworkStats: apply464xlatAdjustments - remove useBpfStats parameter. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: atest NetworkStatsTest NetworkStatsFactoryTest Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: I0121a4ac7ee824adc5930bab786d550b2f00b05b Merged-In: I0121a4ac7ee824adc5930bab786d550b2f00b05b --- core/java/android/net/NetworkStats.java | 7 +++---- .../com/android/server/net/NetworkStatsFactory.java | 10 ++++------ .../com/android/server/net/NetworkStatsService.java | 5 ++--- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 3141320a16..ea0889276c 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1069,11 +1069,10 @@ public final class NetworkStats implements Parcelable { * @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. - * @param useBpfStats True if eBPF is in use. * @hide */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, Map stackedIfaces, boolean useBpfStats) { + NetworkStats stackedTraffic, Map stackedIfaces) { // For recycling Entry entry = null; for (int i = 0; i < stackedTraffic.size; i++) { @@ -1113,8 +1112,8 @@ public final class NetworkStats implements Parcelable { * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. * @hide */ - public void apply464xlatAdjustments(Map stackedIfaces, boolean useBpfStats) { - apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats); + public void apply464xlatAdjustments(Map stackedIfaces) { + apply464xlatAdjustments(this, this, stackedIfaces); } /** diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 3dac106418..86ad0b3086 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -152,12 +152,10 @@ public class NetworkStatsFactory { /** * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. - * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map, boolean) + * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) */ - public void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, boolean useBpfStats) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces, - useBpfStats); + public void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic) { + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces); } public NetworkStatsFactory() { @@ -380,7 +378,7 @@ public class NetworkStatsFactory { // network, the overhead is their fault. // No locking here: apply464xlatAdjustments behaves fine with an add-only // ConcurrentHashMap. - delta.apply464xlatAdjustments(mStackedIfaces, mUseBpfStats); + delta.apply464xlatAdjustments(mStackedIfaces); // Migrate data usage over a VPN to the TUN network. for (VpnInfo info : vpnArray) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index cf5a412321..ba9f486092 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1882,14 +1882,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // 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, - mUseBpfTrafficStats); + 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, mUseBpfTrafficStats); + mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats); uidSnapshot.combineAllValues(providerStats); uidSnapshot.combineAllValues(mUidOperations); From 9d862381bbd371beacb69b5229518f888e0dfe0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 May 2020 01:33:52 -0700 Subject: [PATCH 46/49] NetworkStats: apply464xlatAdjustments - don't remove CLAT_UID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should no longer be needed after all the cleanups. Test: atest NetworkStatsTest NetworkStatsFactoryTest Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: I289d935f84b616ed857ef4c5a7427d57c282d00c Merged-In: I289d935f84b616ed857ef4c5a7427d57c282d00c --- core/java/android/net/NetworkStats.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index ea0889276c..34e48eb44f 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,8 +16,6 @@ package android.net; -import static android.os.Process.CLAT_UID; - import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1095,12 +1093,6 @@ public final class NetworkStats implements Parcelable { entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; stackedTraffic.setValues(i, entry); } - - // Theoretically there should be no traffic accounted to the clat daemon's uid: - // see ebpf program 'netd.c's early returns - // and iptables '-m owner --uid-owner clat -j RETURN' rules prior to accounting - // TODO: remove this - should definitely be safe once ebpf only. - baseTraffic.removeUids(new int[] {CLAT_UID}); } /** From da12e7f732e51e01dc4d9450db70a6fe443f400b Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 28 Apr 2020 18:07:42 +0800 Subject: [PATCH 47/49] Add unit test for NetworkStatsSubscriptionsMonitor Bug: 154080205 Test: atest FrameworksNetTests:com.android.server.net.NetworkStatsSubscriptionsMonitorTest Change-Id: I4ef3f1ab2e5ea1322133edd80db3ccd0022e9c91 --- .../server/net/NetworkStatsSubscriptionsMonitor.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 0bdf3f22ee..a0ab5eae73 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -28,6 +28,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.CollectionUtils; import java.util.ArrayList; @@ -38,8 +39,6 @@ import java.util.concurrent.Executor; /** * Helper class that watches for events that are triggered per subscription. */ -// TODO (b/152176562): Write tests to verify subscription changes generate corresponding -// register/unregister calls. public class NetworkStatsSubscriptionsMonitor extends SubscriptionManager.OnSubscriptionsChangedListener { @@ -207,5 +206,10 @@ public class NetworkStatsSubscriptionsMonitor extends mLastCollapsedRatType = collapsedRatType; mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); } + + @VisibleForTesting + public int getSubId() { + return mSubId; + } } } From 3dae8b1b41c2cee6ee9ebb369442d115aeb5921f Mon Sep 17 00:00:00 2001 From: Michael Groover Date: Fri, 19 Jun 2020 19:48:07 -0700 Subject: [PATCH 48/49] Update docs for methods that require subscriberId In Android 10 additional restrictions were required to access the subscriberId. The NetworkStatsManager has several methods that accept a subscriberId of the mobile network for which usage should be queried. This commit updates the docs for these methods to reference the new access restrictions and offer null as an option to obtain the usage for all mobile networks. Fixes: 157871064 Test: m docs Change-Id: I95c730c9418fced6312eb3ba4e0d69e6299f3ded --- .../app/usage/NetworkStatsManager.java | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index d6e77624a9..fc8248e101 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -41,6 +41,7 @@ import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; +import android.telephony.TelephonyManager; import android.util.DataUnit; import android.util.Log; @@ -198,6 +199,12 @@ public class NetworkStatsManager { * {@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()}. * @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 @@ -231,6 +238,12 @@ public class NetworkStatsManager { * {@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()}. * @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 @@ -268,6 +281,12 @@ public class NetworkStatsManager { * {@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()}. * @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 @@ -301,7 +320,7 @@ public class NetworkStatsManager { /** * Query network usage statistics details for a given uid. * - * #see queryDetailsForUidTagState(int, String, long, long, int, int, int) + * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) */ public NetworkStats queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTime, int uid) throws SecurityException { @@ -319,7 +338,7 @@ public class NetworkStatsManager { /** * Query network usage statistics details for a given uid and tag. * - * #see queryDetailsForUidTagState(int, String, long, long, int, int, int) + * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) */ public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, long startTime, long endTime, int uid, int tag) throws SecurityException { @@ -344,6 +363,12 @@ public class NetworkStatsManager { * {@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()}. * @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 @@ -398,6 +423,12 @@ public class NetworkStatsManager { * {@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()}. * @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 @@ -455,7 +486,7 @@ public class NetworkStatsManager { /** * Registers to receive notifications about data usage on specified networks. * - * #see registerUsageCallback(int, String[], long, UsageCallback, Handler) + * @see #registerUsageCallback(int, String, long, UsageCallback, Handler) */ public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, UsageCallback callback) { @@ -472,6 +503,12 @@ public class NetworkStatsManager { * @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()}. * @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. From fba76f64a6862d31618d964fbe42bd71739a5263 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 16 Jul 2020 13:48:09 +0800 Subject: [PATCH 49/49] Attribute data usage to virtual RAT type for 5G non-standalone mode Test: atest NetworkStatsSubscriptionsMonitorTest#test5g Bug: 160727498 Change-Id: I8753e68140c0993773017c9a49bd8a666a364071 Merged-In: I8753e68140c0993773017c9a49bd8a666a364071 (cherry-picked from ag/12167624) --- core/java/android/net/NetworkTemplate.java | 12 ++++++++++++ .../net/NetworkStatsSubscriptionsMonitor.java | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index eba7ff3483..7234eb1d81 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -87,6 +87,15 @@ public class NetworkTemplate implements Parcelable { * @hide */ public static final int NETWORK_TYPE_ALL = -1; + /** + * 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 should not be overlapped with any of the + * {@code TelephonyManager.NETWORK_TYPE_*} constants. + * + * @hide + */ + public static final int NETWORK_TYPE_5G_NSA = -2; private static boolean isKnownMatchRule(final int rule) { switch (rule) { @@ -475,6 +484,9 @@ public class NetworkTemplate implements Parcelable { return TelephonyManager.NETWORK_TYPE_LTE; case TelephonyManager.NETWORK_TYPE_NR: return TelephonyManager.NETWORK_TYPE_NR; + // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. + case NetworkTemplate.NETWORK_TYPE_5G_NSA: + return NetworkTemplate.NETWORK_TYPE_5G_NSA; default: return TelephonyManager.NETWORK_TYPE_UNKNOWN; } diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index a0ab5eae73..cb1c7e4fd0 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -16,11 +16,13 @@ package com.android.server.net; +import static android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA; import static android.net.NetworkTemplate.getCollapsedRatType; import android.annotation.NonNull; import android.content.Context; import android.telephony.Annotation; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; @@ -195,7 +197,18 @@ public class NetworkStatsSubscriptionsMonitor extends @Override public void onServiceStateChanged(@NonNull ServiceState ss) { - final int networkType = ss.getDataNetworkType(); + // 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 = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE + || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA) + && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED; + + final int networkType = + (is5GNsa ? NETWORK_TYPE_5G_NSA : ss.getDataNetworkType()); final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return;