diff options
8 files changed, 259 insertions, 2 deletions
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index c704ef0c9ca7..0775bdaaf380 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -24,8 +24,10 @@ import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; +import android.service.NetworkIdentityProto; import android.telephony.TelephonyManager; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import java.util.Objects; @@ -110,6 +112,23 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { return builder.append("}").toString(); } + public void writeToProto(ProtoOutputStream proto, long tag) { + final long start = proto.start(tag); + + proto.write(NetworkIdentityProto.TYPE, mType); + + // Not dumping mSubType, subtypes are no longer supported. + + if (mSubscriberId != null) { + proto.write(NetworkIdentityProto.SUBSCRIBER_ID, scrubSubscriberId(mSubscriberId)); + } + proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId); + proto.write(NetworkIdentityProto.ROAMING, mRoaming); + proto.write(NetworkIdentityProto.METERED, mMetered); + + proto.end(start); + } + public int getType() { return mType; } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 4a4accbba502..5f521de63cf1 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -31,7 +31,10 @@ import static com.android.internal.util.ArrayUtils.total; import android.os.Parcel; import android.os.Parcelable; +import android.service.NetworkStatsHistoryBucketProto; +import android.service.NetworkStatsHistoryProto; import android.util.MathUtils; +import android.util.proto.ProtoOutputStream; import com.android.internal.util.IndentingPrintWriter; @@ -628,6 +631,33 @@ public class NetworkStatsHistory implements Parcelable { } } + public void writeToProto(ProtoOutputStream proto, long tag) { + final long start = proto.start(tag); + + proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); + + for (int i = 0; i < bucketCount; i++) { + final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); + + proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]); + 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); + + proto.end(startBucket); + } + + proto.end(start); + } + + private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) { + if (array != null) { + proto.write(tag, array[index]); + } + } + @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index ec2f32b630a0..c3b0ff10b2d8 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -21,6 +21,7 @@ option java_outer_classname = "IncidentProtoMetadata"; import "frameworks/base/libs/incident/proto/android/privacy.proto"; import "frameworks/base/core/proto/android/service/fingerprint.proto"; +import "frameworks/base/core/proto/android/service/netstats.proto"; package android.os; @@ -49,4 +50,5 @@ message IncidentProto { // System Services android.service.fingerprint.FingerprintServiceDumpProto fingerprint = 3000; + android.service.NetworkStatsServiceDumpProto netstats = 3001; } diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto new file mode 100644 index 000000000000..5cca6ab07a6d --- /dev/null +++ b/core/proto/android/service/netstats.proto @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto3"; + +package android.service; + +option java_multiple_files = true; +option java_outer_classname = "NetworkStatsServiceProto"; + +// Represents dumpsys from NetworkStatsService (netstats). +message NetworkStatsServiceDumpProto { + repeated NetworkInterfaceProto active_interfaces = 1; + + repeated NetworkInterfaceProto active_uid_interfaces = 2; + + NetworkStatsRecorderProto dev_stats = 3; + + NetworkStatsRecorderProto xt_stats = 4; + + NetworkStatsRecorderProto uid_stats = 5; + + NetworkStatsRecorderProto uid_tag_stats = 6; +} + +// Corresponds to NetworkStatsService.mActiveIfaces/mActiveUidIfaces. +message NetworkInterfaceProto { + string interface = 1; + + NetworkIdentitySetProto identities = 2; +} + +// Corresponds to NetworkIdentitySet. +message NetworkIdentitySetProto { + repeated NetworkIdentityProto identities = 1; +} + +// Corresponds to NetworkIdentity. +message NetworkIdentityProto { + // Constats from ConnectivityManager.TYPE_*. + int32 type = 1; + + string subscriber_id = 2; + + string network_id = 3; + + bool roaming = 4; + + bool metered = 5; +} + +// Corresponds to NetworkStatsRecorder. +message NetworkStatsRecorderProto { + int64 pending_total_bytes = 1; + + NetworkStatsCollectionProto complete_history = 2; +} + +// Corresponds to NetworkStatsCollection. +message NetworkStatsCollectionProto { + repeated NetworkStatsCollectionStatsProto stats = 1; +} + +// Corresponds to NetworkStatsCollection.mStats. +message NetworkStatsCollectionStatsProto { + NetworkStatsCollectionKeyProto key = 1; + + NetworkStatsHistoryProto history = 2; +} + +// Corresponds to NetworkStatsCollection.Key. +message NetworkStatsCollectionKeyProto { + NetworkIdentitySetProto identity = 1; + + int32 uid = 2; + + int32 set = 3; + + int32 tag = 4; +} + +// Corresponds to NetworkStatsHistory. +message NetworkStatsHistoryProto { + // Duration for this bucket in milliseconds. + int64 bucket_duration_ms = 1; + + repeated NetworkStatsHistoryBucketProto buckets = 2; +} + +// Corresponds to each bucket in NetworkStatsHistory. +message NetworkStatsHistoryBucketProto { + // Bucket start time in milliseconds since epoch. + int64 bucket_start_ms = 1; + + int64 rx_bytes = 2; + + int64 rx_packets = 3; + + int64 tx_bytes = 4; + + int64 tx_packets = 5; + + int64 operations = 6; +} diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index c48f43058fca..ee00fdc33367 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -17,6 +17,8 @@ package com.android.server.net; import android.net.NetworkIdentity; +import android.service.NetworkIdentitySetProto; +import android.util.proto.ProtoOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -143,4 +145,14 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements final NetworkIdentity anotherIdent = another.iterator().next(); return ident.compareTo(anotherIdent); } + + public void writeToProto(ProtoOutputStream proto, long tag) { + final long start = proto.start(tag); + + for (NetworkIdentity ident : this) { + ident.writeToProto(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 c45b4169f575..03543007c80e 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -34,9 +34,13 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.os.Binder; +import android.service.NetworkStatsCollectionKeyProto; +import android.service.NetworkStatsCollectionProto; +import android.service.NetworkStatsCollectionStatsProto; import android.util.ArrayMap; import android.util.AtomicFile; import android.util.IntArray; +import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; @@ -532,12 +536,15 @@ public class NetworkStatsCollection implements FileRotator.Reader { / mBucketDuration); } - public void dump(IndentingPrintWriter pw) { + private ArrayList<Key> getSortedKeys() { final ArrayList<Key> keys = Lists.newArrayList(); keys.addAll(mStats.keySet()); Collections.sort(keys); + return keys; + } - for (Key key : keys) { + public void dump(IndentingPrintWriter pw) { + for (Key key : getSortedKeys()) { pw.print("ident="); pw.print(key.ident.toString()); pw.print(" uid="); pw.print(key.uid); pw.print(" set="); pw.print(NetworkStats.setToString(key.set)); @@ -550,6 +557,29 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } + public void writeToProto(ProtoOutputStream proto, long tag) { + final long start = proto.start(tag); + + for (Key key : getSortedKeys()) { + final long startStats = proto.start(NetworkStatsCollectionProto.STATS); + + // Key + final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); + key.ident.writeToProto(proto, NetworkStatsCollectionKeyProto.IDENTITY); + proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); + proto.write(NetworkStatsCollectionKeyProto.SET, key.set); + proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); + proto.end(startKey); + + // Value + final NetworkStatsHistory history = mStats.get(key); + history.writeToProto(proto, NetworkStatsCollectionStatsProto.HISTORY); + proto.end(startStats); + } + + proto.end(start); + } + public void dumpCheckin(PrintWriter pw, long start, long end) { dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell"); dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi"); diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index 090a0762a4b5..80309e19eb42 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -29,9 +29,11 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.os.DropBoxManager; +import android.service.NetworkStatsRecorderProto; import android.util.Log; import android.util.MathUtils; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; @@ -465,6 +467,15 @@ public class NetworkStatsRecorder { } } + public void writeToProtoLocked(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); + proto.end(start); + } + public void dumpCheckin(PrintWriter pw, long start, long end) { // Only load and dump stats from the requested window getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 386e78b5181d..104c29619c96 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -104,6 +104,8 @@ import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Global; +import android.service.NetworkInterfaceProto; +import android.service.NetworkStatsServiceDumpProto; import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.ArrayMap; @@ -115,6 +117,7 @@ import android.util.NtpTrustedTime; import android.util.Slog; import android.util.SparseIntArray; import android.util.TrustedTime; +import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.net.VpnInfo; @@ -1255,6 +1258,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " "); synchronized (mStatsLock) { + if (args.length > 0 && "--proto".equals(args[0])) { + // In this case ignore all other arguments. + dumpProto(fd); + return; + } + if (poll) { performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE); pw.println("Forced poll"); @@ -1327,6 +1336,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + private void dumpProto(FileDescriptor fd) { + final ProtoOutputStream proto = new ProtoOutputStream(fd); + + // TODO Right now it writes all history. Should it limit to the "since-boot" log? + + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces); + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces); + mDevRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); + mXtRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); + mUidRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); + mUidTagRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS); + + proto.flush(); + } + + private static void dumpInterfaces(ProtoOutputStream proto, long tag, + ArrayMap<String, NetworkIdentitySet> ifaces) { + for (int i = 0; i < ifaces.size(); i++) { + final long start = proto.start(tag); + + proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); + ifaces.valueAt(i).writeToProto(proto, NetworkInterfaceProto.IDENTITIES); + + proto.end(start); + } + } + /** * Return snapshot of current UID statistics, including any * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values. |