Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.server.connectivity; |
| 18 | |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 19 | import static android.util.TimeUtils.NANOS_PER_MS; |
| 20 | |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 21 | import android.content.Context; |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 22 | import android.net.ConnectivityManager; |
Michal Karpinski | dd9bb4f | 2016-10-12 14:59:26 +0100 | [diff] [blame] | 23 | import android.net.INetdEventCallback; |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 24 | import android.net.Network; |
Hugo Benichi | 2a5cfb9 | 2017-03-22 22:21:44 +0900 | [diff] [blame] | 25 | import android.net.NetworkCapabilities; |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 26 | import android.net.metrics.ConnectStats; |
Hugo Benichi | 5e05518 | 2016-06-01 08:50:38 +0900 | [diff] [blame] | 27 | import android.net.metrics.DnsEvent; |
Michal Karpinski | d11d18c | 2016-09-15 17:07:08 +0900 | [diff] [blame] | 28 | import android.net.metrics.INetdEventListener; |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 29 | import android.net.metrics.IpConnectivityLog; |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 30 | import android.net.metrics.NetworkMetrics; |
Hugo Benichi | f562ac3 | 2017-09-04 13:24:43 +0900 | [diff] [blame] | 31 | import android.net.metrics.WakeupEvent; |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 32 | import android.net.metrics.WakeupStats; |
Michal Karpinski | dd9bb4f | 2016-10-12 14:59:26 +0100 | [diff] [blame] | 33 | import android.os.RemoteException; |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 34 | import android.text.format.DateUtils; |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 35 | import android.util.Log; |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 36 | import android.util.ArrayMap; |
Hugo Benichi | 2a5cfb9 | 2017-03-22 22:21:44 +0900 | [diff] [blame] | 37 | import android.util.SparseArray; |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 38 | |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 39 | import com.android.internal.annotations.GuardedBy; |
Hugo Benichi | 5e05518 | 2016-06-01 08:50:38 +0900 | [diff] [blame] | 40 | import com.android.internal.annotations.VisibleForTesting; |
Hugo Benichi | 2a5cfb9 | 2017-03-22 22:21:44 +0900 | [diff] [blame] | 41 | import com.android.internal.util.BitUtils; |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 42 | import com.android.internal.util.IndentingPrintWriter; |
Hugo Benichi | 67c5e03 | 2017-09-14 16:31:38 +0900 | [diff] [blame] | 43 | import com.android.internal.util.RingBuffer; |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 44 | import com.android.internal.util.TokenBucket; |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 45 | import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 46 | |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 47 | import java.io.PrintWriter; |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 48 | import java.util.ArrayList; |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 49 | import java.util.List; |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 50 | import java.util.StringJoiner; |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 51 | |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 52 | /** |
Michal Karpinski | d11d18c | 2016-09-15 17:07:08 +0900 | [diff] [blame] | 53 | * Implementation of the INetdEventListener interface. |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 54 | */ |
Michal Karpinski | d11d18c | 2016-09-15 17:07:08 +0900 | [diff] [blame] | 55 | public class NetdEventListenerService extends INetdEventListener.Stub { |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 56 | |
Michal Karpinski | d11d18c | 2016-09-15 17:07:08 +0900 | [diff] [blame] | 57 | public static final String SERVICE_NAME = "netd_listener"; |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 58 | |
Michal Karpinski | d11d18c | 2016-09-15 17:07:08 +0900 | [diff] [blame] | 59 | private static final String TAG = NetdEventListenerService.class.getSimpleName(); |
Hugo Benichi | 8b06bcd | 2016-10-31 15:04:37 +0900 | [diff] [blame] | 60 | private static final boolean DBG = false; |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 61 | private static final boolean VDBG = false; |
| 62 | |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 63 | // Rate limit connect latency logging to 1 measurement per 15 seconds (5760 / day) with maximum |
| 64 | // bursts of 5000 measurements. |
| 65 | private static final int CONNECT_LATENCY_BURST_LIMIT = 5000; |
| 66 | private static final int CONNECT_LATENCY_FILL_RATE = 15 * (int) DateUtils.SECOND_IN_MILLIS; |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 67 | |
| 68 | private static final long METRICS_SNAPSHOT_SPAN_MS = 5 * DateUtils.MINUTE_IN_MILLIS; |
| 69 | private static final int METRICS_SNAPSHOT_BUFFER_SIZE = 48; // 4 hours |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 70 | |
Hugo Benichi | f562ac3 | 2017-09-04 13:24:43 +0900 | [diff] [blame] | 71 | @VisibleForTesting |
| 72 | static final int WAKEUP_EVENT_BUFFER_LENGTH = 1024; |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 73 | // TODO: dedup this String constant with the one used in |
| 74 | // ConnectivityService#wakeupModifyInterface(). |
| 75 | @VisibleForTesting |
| 76 | static final String WAKEUP_EVENT_IFACE_PREFIX = "iface:"; |
Hugo Benichi | f562ac3 | 2017-09-04 13:24:43 +0900 | [diff] [blame] | 77 | |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 78 | // Array of aggregated DNS and connect events sent by netd, grouped by net id. |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 79 | @GuardedBy("this") |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 80 | private final SparseArray<NetworkMetrics> mNetworkMetrics = new SparseArray<>(); |
| 81 | |
Hugo Benichi | 5eb9053 | 2017-03-23 18:38:22 +0900 | [diff] [blame] | 82 | @GuardedBy("this") |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 83 | private final RingBuffer<NetworkMetricsSnapshot> mNetworkMetricsSnapshots = |
| 84 | new RingBuffer<>(NetworkMetricsSnapshot.class, METRICS_SNAPSHOT_BUFFER_SIZE); |
| 85 | @GuardedBy("this") |
| 86 | private long mLastSnapshot = 0; |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 87 | |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 88 | // Array of aggregated wakeup event stats, grouped by interface name. |
| 89 | @GuardedBy("this") |
| 90 | private final ArrayMap<String, WakeupStats> mWakeupStats = new ArrayMap<>(); |
Hugo Benichi | f562ac3 | 2017-09-04 13:24:43 +0900 | [diff] [blame] | 91 | // Ring buffer array for storing packet wake up events sent by Netd. |
| 92 | @GuardedBy("this") |
Hugo Benichi | 67c5e03 | 2017-09-14 16:31:38 +0900 | [diff] [blame] | 93 | private final RingBuffer<WakeupEvent> mWakeupEvents = |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 94 | new RingBuffer<>(WakeupEvent.class, WAKEUP_EVENT_BUFFER_LENGTH); |
Hugo Benichi | f562ac3 | 2017-09-04 13:24:43 +0900 | [diff] [blame] | 95 | |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 96 | private final ConnectivityManager mCm; |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 97 | |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 98 | @GuardedBy("this") |
| 99 | private final TokenBucket mConnectTb = |
| 100 | new TokenBucket(CONNECT_LATENCY_FILL_RATE, CONNECT_LATENCY_BURST_LIMIT); |
Michal Karpinski | dd9bb4f | 2016-10-12 14:59:26 +0100 | [diff] [blame] | 101 | // Callback should only be registered/unregistered when logging is being enabled/disabled in DPM |
| 102 | // by the device owner. It's DevicePolicyManager's responsibility to ensure that. |
| 103 | @GuardedBy("this") |
| 104 | private INetdEventCallback mNetdEventCallback; |
| 105 | |
| 106 | public synchronized boolean registerNetdEventCallback(INetdEventCallback callback) { |
| 107 | mNetdEventCallback = callback; |
| 108 | return true; |
| 109 | } |
| 110 | |
| 111 | public synchronized boolean unregisterNetdEventCallback() { |
| 112 | mNetdEventCallback = null; |
| 113 | return true; |
| 114 | } |
| 115 | |
Michal Karpinski | d11d18c | 2016-09-15 17:07:08 +0900 | [diff] [blame] | 116 | public NetdEventListenerService(Context context) { |
Hugo Benichi | 2a5cfb9 | 2017-03-22 22:21:44 +0900 | [diff] [blame] | 117 | this(context.getSystemService(ConnectivityManager.class)); |
Hugo Benichi | 5e05518 | 2016-06-01 08:50:38 +0900 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | @VisibleForTesting |
Hugo Benichi | 2a5cfb9 | 2017-03-22 22:21:44 +0900 | [diff] [blame] | 121 | public NetdEventListenerService(ConnectivityManager cm) { |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 122 | // We are started when boot is complete, so ConnectivityService should already be running. |
Hugo Benichi | 5e05518 | 2016-06-01 08:50:38 +0900 | [diff] [blame] | 123 | mCm = cm; |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 124 | } |
| 125 | |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 126 | private static long projectSnapshotTime(long timeMs) { |
| 127 | return (timeMs / METRICS_SNAPSHOT_SPAN_MS) * METRICS_SNAPSHOT_SPAN_MS; |
| 128 | } |
| 129 | |
| 130 | private NetworkMetrics getMetricsForNetwork(long timeMs, int netId) { |
| 131 | collectPendingMetricsSnapshot(timeMs); |
| 132 | NetworkMetrics metrics = mNetworkMetrics.get(netId); |
| 133 | if (metrics == null) { |
| 134 | // TODO: allow to change transport for a given netid. |
| 135 | metrics = new NetworkMetrics(netId, getTransports(netId), mConnectTb); |
| 136 | mNetworkMetrics.put(netId, metrics); |
| 137 | } |
| 138 | return metrics; |
| 139 | } |
| 140 | |
| 141 | private NetworkMetricsSnapshot[] getNetworkMetricsSnapshots() { |
| 142 | collectPendingMetricsSnapshot(System.currentTimeMillis()); |
| 143 | return mNetworkMetricsSnapshots.toArray(); |
| 144 | } |
| 145 | |
| 146 | private void collectPendingMetricsSnapshot(long timeMs) { |
| 147 | // Detects time differences larger than the snapshot collection period. |
| 148 | // This is robust against clock jumps and long inactivity periods. |
| 149 | if (Math.abs(timeMs - mLastSnapshot) <= METRICS_SNAPSHOT_SPAN_MS) { |
| 150 | return; |
| 151 | } |
| 152 | mLastSnapshot = projectSnapshotTime(timeMs); |
| 153 | NetworkMetricsSnapshot snapshot = |
| 154 | NetworkMetricsSnapshot.collect(mLastSnapshot, mNetworkMetrics); |
| 155 | if (snapshot.stats.isEmpty()) { |
| 156 | return; |
| 157 | } |
| 158 | mNetworkMetricsSnapshots.append(snapshot); |
| 159 | } |
| 160 | |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 161 | @Override |
| 162 | // Called concurrently by multiple binder threads. |
Michal Karpinski | 14c9d2d | 2016-09-27 17:13:57 +0100 | [diff] [blame] | 163 | // This method must not block or perform long-running operations. |
| 164 | public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, |
Michal Karpinski | dd9bb4f | 2016-10-12 14:59:26 +0100 | [diff] [blame] | 165 | String hostname, String[] ipAddresses, int ipAddressesCount, int uid) |
| 166 | throws RemoteException { |
Hugo Benichi | 8b06bcd | 2016-10-31 15:04:37 +0900 | [diff] [blame] | 167 | maybeVerboseLog("onDnsEvent(%d, %d, %d, %dms)", netId, eventType, returnCode, latencyMs); |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 168 | |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 169 | long timestamp = System.currentTimeMillis(); |
| 170 | getMetricsForNetwork(timestamp, netId).addDnsResult(eventType, returnCode, latencyMs); |
Michal Karpinski | dd9bb4f | 2016-10-12 14:59:26 +0100 | [diff] [blame] | 171 | |
| 172 | if (mNetdEventCallback != null) { |
Hugo Benichi | 2a5cfb9 | 2017-03-22 22:21:44 +0900 | [diff] [blame] | 173 | mNetdEventCallback.onDnsEvent(hostname, ipAddresses, ipAddressesCount, timestamp, uid); |
Michal Karpinski | dd9bb4f | 2016-10-12 14:59:26 +0100 | [diff] [blame] | 174 | } |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 175 | } |
| 176 | |
Michal Karpinski | 965894e | 2016-09-28 16:06:16 +0100 | [diff] [blame] | 177 | @Override |
| 178 | // Called concurrently by multiple binder threads. |
| 179 | // This method must not block or perform long-running operations. |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 180 | public synchronized void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, |
| 181 | int port, int uid) throws RemoteException { |
Hugo Benichi | 8b06bcd | 2016-10-31 15:04:37 +0900 | [diff] [blame] | 182 | maybeVerboseLog("onConnectEvent(%d, %d, %dms)", netId, error, latencyMs); |
Michal Karpinski | dd9bb4f | 2016-10-12 14:59:26 +0100 | [diff] [blame] | 183 | |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 184 | long timestamp = System.currentTimeMillis(); |
| 185 | getMetricsForNetwork(timestamp, netId).addConnectResult(error, latencyMs, ipAddr); |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 186 | |
Michal Karpinski | dd9bb4f | 2016-10-12 14:59:26 +0100 | [diff] [blame] | 187 | if (mNetdEventCallback != null) { |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 188 | mNetdEventCallback.onConnectEvent(ipAddr, port, timestamp, uid); |
Michal Karpinski | dd9bb4f | 2016-10-12 14:59:26 +0100 | [diff] [blame] | 189 | } |
Michal Karpinski | 965894e | 2016-09-28 16:06:16 +0100 | [diff] [blame] | 190 | } |
| 191 | |
Joel Scherpelz | b369bf5 | 2017-05-22 13:47:41 +0900 | [diff] [blame] | 192 | @Override |
| 193 | public synchronized void onWakeupEvent(String prefix, int uid, int gid, long timestampNs) { |
Hugo Benichi | f562ac3 | 2017-09-04 13:24:43 +0900 | [diff] [blame] | 194 | maybeVerboseLog("onWakeupEvent(%s, %d, %d, %sns)", prefix, uid, gid, timestampNs); |
| 195 | |
| 196 | // TODO: add ip protocol and port |
| 197 | |
| 198 | String iface = prefix.replaceFirst(WAKEUP_EVENT_IFACE_PREFIX, ""); |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 199 | final long timestampMs; |
| 200 | if (timestampNs > 0) { |
| 201 | timestampMs = timestampNs / NANOS_PER_MS; |
| 202 | } else { |
| 203 | timestampMs = System.currentTimeMillis(); |
| 204 | } |
Hugo Benichi | f562ac3 | 2017-09-04 13:24:43 +0900 | [diff] [blame] | 205 | |
Hugo Benichi | 175b574 | 2017-09-19 13:15:26 +0900 | [diff] [blame] | 206 | addWakeupEvent(iface, timestampMs, uid); |
Hugo Benichi | f562ac3 | 2017-09-04 13:24:43 +0900 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | @GuardedBy("this") |
Hugo Benichi | 175b574 | 2017-09-19 13:15:26 +0900 | [diff] [blame] | 210 | private void addWakeupEvent(String iface, long timestampMs, int uid) { |
Hugo Benichi | f562ac3 | 2017-09-04 13:24:43 +0900 | [diff] [blame] | 211 | WakeupEvent event = new WakeupEvent(); |
| 212 | event.iface = iface; |
| 213 | event.timestampMs = timestampMs; |
| 214 | event.uid = uid; |
Hugo Benichi | 67c5e03 | 2017-09-14 16:31:38 +0900 | [diff] [blame] | 215 | mWakeupEvents.append(event); |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 216 | WakeupStats stats = mWakeupStats.get(iface); |
| 217 | if (stats == null) { |
| 218 | stats = new WakeupStats(iface); |
| 219 | mWakeupStats.put(iface, stats); |
| 220 | } |
| 221 | stats.countEvent(event); |
Hugo Benichi | f562ac3 | 2017-09-04 13:24:43 +0900 | [diff] [blame] | 222 | } |
| 223 | |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 224 | public synchronized void flushStatistics(List<IpConnectivityEvent> events) { |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 225 | for (int i = 0; i < mNetworkMetrics.size(); i++) { |
| 226 | ConnectStats stats = mNetworkMetrics.valueAt(i).connectMetrics; |
| 227 | if (stats.eventCount == 0) { |
| 228 | continue; |
| 229 | } |
| 230 | events.add(IpConnectivityEventBuilder.toProto(stats)); |
| 231 | } |
| 232 | for (int i = 0; i < mNetworkMetrics.size(); i++) { |
| 233 | DnsEvent ev = mNetworkMetrics.valueAt(i).dnsMetrics; |
| 234 | if (ev.eventCount == 0) { |
| 235 | continue; |
| 236 | } |
| 237 | events.add(IpConnectivityEventBuilder.toProto(ev)); |
| 238 | } |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 239 | for (int i = 0; i < mWakeupStats.size(); i++) { |
| 240 | events.add(IpConnectivityEventBuilder.toProto(mWakeupStats.valueAt(i))); |
| 241 | } |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 242 | mNetworkMetrics.clear(); |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 243 | mWakeupStats.clear(); |
Hugo Benichi | 0d4a398 | 2016-11-25 11:24:22 +0900 | [diff] [blame] | 244 | } |
| 245 | |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 246 | public synchronized void dump(PrintWriter writer) { |
| 247 | IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); |
| 248 | pw.println(TAG + ":"); |
| 249 | pw.increaseIndent(); |
Hugo Benichi | a2decca | 2017-02-22 14:32:27 +0900 | [diff] [blame] | 250 | list(pw); |
| 251 | pw.decreaseIndent(); |
| 252 | } |
| 253 | |
| 254 | public synchronized void list(PrintWriter pw) { |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 255 | for (int i = 0; i < mNetworkMetrics.size(); i++) { |
| 256 | pw.println(mNetworkMetrics.valueAt(i).connectMetrics); |
| 257 | } |
| 258 | for (int i = 0; i < mNetworkMetrics.size(); i++) { |
| 259 | pw.println(mNetworkMetrics.valueAt(i).dnsMetrics); |
| 260 | } |
| 261 | for (NetworkMetricsSnapshot s : getNetworkMetricsSnapshots()) { |
| 262 | pw.println(s); |
| 263 | } |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 264 | for (int i = 0; i < mWakeupStats.size(); i++) { |
| 265 | pw.println(mWakeupStats.valueAt(i)); |
| 266 | } |
Hugo Benichi | 67c5e03 | 2017-09-14 16:31:38 +0900 | [diff] [blame] | 267 | for (WakeupEvent wakeup : mWakeupEvents.toArray()) { |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 268 | pw.println(wakeup); |
| 269 | } |
Hugo Benichi | a2decca | 2017-02-22 14:32:27 +0900 | [diff] [blame] | 270 | } |
| 271 | |
| 272 | public synchronized void listAsProtos(PrintWriter pw) { |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 273 | for (int i = 0; i < mNetworkMetrics.size(); i++) { |
| 274 | pw.print(IpConnectivityEventBuilder.toProto(mNetworkMetrics.valueAt(i).connectMetrics)); |
| 275 | } |
| 276 | for (int i = 0; i < mNetworkMetrics.size(); i++) { |
| 277 | pw.print(IpConnectivityEventBuilder.toProto(mNetworkMetrics.valueAt(i).dnsMetrics)); |
| 278 | } |
Hugo Benichi | 60c9f63 | 2017-09-05 13:34:48 +0900 | [diff] [blame] | 279 | for (int i = 0; i < mWakeupStats.size(); i++) { |
| 280 | pw.print(IpConnectivityEventBuilder.toProto(mWakeupStats.valueAt(i))); |
| 281 | } |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 282 | } |
| 283 | |
Hugo Benichi | 2a5cfb9 | 2017-03-22 22:21:44 +0900 | [diff] [blame] | 284 | private long getTransports(int netId) { |
| 285 | // TODO: directly query ConnectivityService instead of going through Binder interface. |
| 286 | NetworkCapabilities nc = mCm.getNetworkCapabilities(new Network(netId)); |
| 287 | if (nc == null) { |
| 288 | return 0; |
| 289 | } |
| 290 | return BitUtils.packBits(nc.getTransportTypes()); |
| 291 | } |
| 292 | |
Hugo Benichi | 8b06bcd | 2016-10-31 15:04:37 +0900 | [diff] [blame] | 293 | private static void maybeLog(String s, Object... args) { |
| 294 | if (DBG) Log.d(TAG, String.format(s, args)); |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 295 | } |
| 296 | |
Hugo Benichi | 8b06bcd | 2016-10-31 15:04:37 +0900 | [diff] [blame] | 297 | private static void maybeVerboseLog(String s, Object... args) { |
| 298 | if (VDBG) Log.d(TAG, String.format(s, args)); |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 299 | } |
Hugo Benichi | ab20975 | 2017-09-27 23:28:59 +0900 | [diff] [blame] | 300 | |
| 301 | /** Helper class for buffering summaries of NetworkMetrics at regular time intervals */ |
| 302 | static class NetworkMetricsSnapshot { |
| 303 | |
| 304 | public long timeMs; |
| 305 | public List<NetworkMetrics.Summary> stats = new ArrayList<>(); |
| 306 | |
| 307 | static NetworkMetricsSnapshot collect(long timeMs, SparseArray<NetworkMetrics> networkMetrics) { |
| 308 | NetworkMetricsSnapshot snapshot = new NetworkMetricsSnapshot(); |
| 309 | snapshot.timeMs = timeMs; |
| 310 | for (int i = 0; i < networkMetrics.size(); i++) { |
| 311 | NetworkMetrics.Summary s = networkMetrics.valueAt(i).getPendingStats(); |
| 312 | if (s != null) { |
| 313 | snapshot.stats.add(s); |
| 314 | } |
| 315 | } |
| 316 | return snapshot; |
| 317 | } |
| 318 | |
| 319 | @Override |
| 320 | public String toString() { |
| 321 | StringJoiner j = new StringJoiner(", "); |
| 322 | for (NetworkMetrics.Summary s : stats) { |
| 323 | j.add(s.toString()); |
| 324 | } |
| 325 | return String.format("%tT.%tL: %s", timeMs, timeMs, j.toString()); |
| 326 | } |
| 327 | } |
Lorenzo Colitti | 4372473 | 2016-04-12 23:29:19 +0900 | [diff] [blame] | 328 | } |