Hugo Benichi | 64901e5 | 2017-10-19 14:42:40 +0900 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 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 | 64901e5 | 2017-10-19 14:42:40 +0900 | [diff] [blame] | 19 | import android.net.LinkProperties; |
| 20 | import android.net.metrics.DefaultNetworkEvent; |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 21 | import android.os.SystemClock; |
Hugo Benichi | 64901e5 | 2017-10-19 14:42:40 +0900 | [diff] [blame] | 22 | |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 23 | import com.android.internal.annotations.GuardedBy; |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 24 | import com.android.internal.util.BitUtils; |
| 25 | import com.android.internal.util.RingBuffer; |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 26 | import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent; |
| 27 | |
| 28 | import java.io.PrintWriter; |
| 29 | import java.util.ArrayList; |
| 30 | import java.util.List; |
| 31 | |
Hugo Benichi | 64901e5 | 2017-10-19 14:42:40 +0900 | [diff] [blame] | 32 | /** |
| 33 | * Tracks events related to the default network for the purpose of default network metrics. |
| 34 | * {@hide} |
| 35 | */ |
| 36 | public class DefaultNetworkMetrics { |
| 37 | |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 38 | private static final int ROLLING_LOG_SIZE = 64; |
Hugo Benichi | 64901e5 | 2017-10-19 14:42:40 +0900 | [diff] [blame] | 39 | |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 40 | public final long creationTimeMs = SystemClock.elapsedRealtime(); |
| 41 | |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 42 | // Event buffer used for metrics upload. The buffer is cleared when events are collected. |
| 43 | @GuardedBy("this") |
| 44 | private final List<DefaultNetworkEvent> mEvents = new ArrayList<>(); |
Hugo Benichi | 64901e5 | 2017-10-19 14:42:40 +0900 | [diff] [blame] | 45 | |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 46 | // Rolling event buffer used for dumpsys and bugreports. |
| 47 | @GuardedBy("this") |
| 48 | private final RingBuffer<DefaultNetworkEvent> mEventsLog = |
| 49 | new RingBuffer(DefaultNetworkEvent.class, ROLLING_LOG_SIZE); |
| 50 | |
| 51 | // Information about the current status of the default network. |
| 52 | @GuardedBy("this") |
| 53 | private DefaultNetworkEvent mCurrentDefaultNetwork; |
Hugo Benichi | 71a1b53 | 2017-12-06 13:28:09 +0900 | [diff] [blame] | 54 | // True if the current default network has been validated. |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 55 | @GuardedBy("this") |
| 56 | private boolean mIsCurrentlyValid; |
| 57 | @GuardedBy("this") |
| 58 | private long mLastValidationTimeMs; |
| 59 | // Transport information about the last default network. |
| 60 | @GuardedBy("this") |
| 61 | private int mLastTransports; |
| 62 | |
| 63 | public DefaultNetworkMetrics() { |
| 64 | newDefaultNetwork(creationTimeMs, null); |
| 65 | } |
| 66 | |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 67 | public synchronized void listEvents(PrintWriter pw) { |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 68 | pw.println("default network events:"); |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 69 | long localTimeMs = System.currentTimeMillis(); |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 70 | long timeMs = SystemClock.elapsedRealtime(); |
| 71 | for (DefaultNetworkEvent ev : mEventsLog.toArray()) { |
| 72 | printEvent(localTimeMs, pw, ev); |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 73 | } |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 74 | mCurrentDefaultNetwork.updateDuration(timeMs); |
Hugo Benichi | 71a1b53 | 2017-12-06 13:28:09 +0900 | [diff] [blame] | 75 | // When printing default network events for bug reports, update validation time |
| 76 | // and refresh the last validation timestmap for future validation time updates. |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 77 | if (mIsCurrentlyValid) { |
| 78 | updateValidationTime(timeMs); |
| 79 | mLastValidationTimeMs = timeMs; |
| 80 | } |
| 81 | printEvent(localTimeMs, pw, mCurrentDefaultNetwork); |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 82 | } |
| 83 | |
Mike Ma | d2672bd | 2020-01-15 15:57:20 -0800 | [diff] [blame] | 84 | /** |
Mike Ma | e19df93 | 2020-01-22 01:36:32 -0800 | [diff] [blame] | 85 | * Convert events in the ring buffer to a list of IpConnectivityEvent protos |
Mike Ma | d2672bd | 2020-01-15 15:57:20 -0800 | [diff] [blame] | 86 | */ |
Mike Ma | e19df93 | 2020-01-22 01:36:32 -0800 | [diff] [blame] | 87 | public synchronized List<IpConnectivityEvent> listEventsAsProto() { |
| 88 | List<IpConnectivityEvent> list = new ArrayList<>(); |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 89 | for (DefaultNetworkEvent ev : mEventsLog.toArray()) { |
Mike Ma | e19df93 | 2020-01-22 01:36:32 -0800 | [diff] [blame] | 90 | list.add(IpConnectivityEventBuilder.toProto(ev)); |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 91 | } |
Mike Ma | e19df93 | 2020-01-22 01:36:32 -0800 | [diff] [blame] | 92 | return list; |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | public synchronized void flushEvents(List<IpConnectivityEvent> out) { |
| 96 | for (DefaultNetworkEvent ev : mEvents) { |
| 97 | out.add(IpConnectivityEventBuilder.toProto(ev)); |
| 98 | } |
| 99 | mEvents.clear(); |
| 100 | } |
| 101 | |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 102 | public synchronized void logDefaultNetworkValidity(long timeMs, boolean isValid) { |
Hugo Benichi | 71a1b53 | 2017-12-06 13:28:09 +0900 | [diff] [blame] | 103 | // Transition from valid to invalid: update validity duration since last update |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 104 | if (!isValid && mIsCurrentlyValid) { |
| 105 | mIsCurrentlyValid = false; |
| 106 | updateValidationTime(timeMs); |
Hugo Benichi | 64901e5 | 2017-10-19 14:42:40 +0900 | [diff] [blame] | 107 | } |
| 108 | |
Hugo Benichi | 71a1b53 | 2017-12-06 13:28:09 +0900 | [diff] [blame] | 109 | // Transition from invalid to valid: simply mark the validation timestamp. |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 110 | if (isValid && !mIsCurrentlyValid) { |
| 111 | mIsCurrentlyValid = true; |
| 112 | mLastValidationTimeMs = timeMs; |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | private void updateValidationTime(long timeMs) { |
| 117 | mCurrentDefaultNetwork.validatedMs += timeMs - mLastValidationTimeMs; |
| 118 | } |
| 119 | |
| 120 | public synchronized void logDefaultNetworkEvent( |
| 121 | long timeMs, NetworkAgentInfo newNai, NetworkAgentInfo oldNai) { |
| 122 | logCurrentDefaultNetwork(timeMs, oldNai); |
| 123 | newDefaultNetwork(timeMs, newNai); |
| 124 | } |
| 125 | |
| 126 | private void logCurrentDefaultNetwork(long timeMs, NetworkAgentInfo oldNai) { |
Hugo Benichi | 71a1b53 | 2017-12-06 13:28:09 +0900 | [diff] [blame] | 127 | if (mIsCurrentlyValid) { |
| 128 | updateValidationTime(timeMs); |
| 129 | } |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 130 | DefaultNetworkEvent ev = mCurrentDefaultNetwork; |
| 131 | ev.updateDuration(timeMs); |
| 132 | ev.previousTransports = mLastTransports; |
| 133 | // oldNai is null if the system had no default network before the transition. |
| 134 | if (oldNai != null) { |
| 135 | // The system acquired a new default network. |
| 136 | fillLinkInfo(ev, oldNai); |
| 137 | ev.finalScore = oldNai.getCurrentScore(); |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 138 | } |
| 139 | // Only change transport of the previous default network if the event currently logged |
| 140 | // corresponds to an existing default network, and not to the absence of a default network. |
| 141 | // This allows to log pairs of transports for successive default networks regardless of |
| 142 | // whether or not the system experienced a period without any default network. |
| 143 | if (ev.transports != 0) { |
| 144 | mLastTransports = ev.transports; |
| 145 | } |
Hugo Benichi | 1193a9c | 2017-10-19 14:58:15 +0900 | [diff] [blame] | 146 | mEvents.add(ev); |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 147 | mEventsLog.append(ev); |
| 148 | } |
| 149 | |
| 150 | private void newDefaultNetwork(long timeMs, NetworkAgentInfo newNai) { |
| 151 | DefaultNetworkEvent ev = new DefaultNetworkEvent(timeMs); |
| 152 | ev.durationMs = timeMs; |
| 153 | // newNai is null if the system has no default network after the transition. |
| 154 | if (newNai != null) { |
| 155 | fillLinkInfo(ev, newNai); |
| 156 | ev.initialScore = newNai.getCurrentScore(); |
| 157 | if (newNai.lastValidated) { |
Hugo Benichi | bb16b75 | 2017-12-14 09:56:04 +0900 | [diff] [blame] | 158 | mIsCurrentlyValid = true; |
| 159 | mLastValidationTimeMs = timeMs; |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 160 | } |
Hugo Benichi | 71a1b53 | 2017-12-06 13:28:09 +0900 | [diff] [blame] | 161 | } else { |
| 162 | mIsCurrentlyValid = false; |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 163 | } |
| 164 | mCurrentDefaultNetwork = ev; |
| 165 | } |
| 166 | |
| 167 | private static void fillLinkInfo(DefaultNetworkEvent ev, NetworkAgentInfo nai) { |
| 168 | LinkProperties lp = nai.linkProperties; |
| 169 | ev.netId = nai.network().netId; |
| 170 | ev.transports |= BitUtils.packBits(nai.networkCapabilities.getTransportTypes()); |
paulhu | d9736de | 2019-03-08 16:35:20 +0800 | [diff] [blame] | 171 | ev.ipv4 |= lp.hasIpv4Address() && lp.hasIpv4DefaultRoute(); |
| 172 | ev.ipv6 |= lp.hasGlobalIpv6Address() && lp.hasIpv6DefaultRoute(); |
Hugo Benichi | 380a063 | 2017-10-20 09:25:29 +0900 | [diff] [blame] | 173 | } |
| 174 | |
| 175 | private static void printEvent(long localTimeMs, PrintWriter pw, DefaultNetworkEvent ev) { |
| 176 | long localCreationTimeMs = localTimeMs - ev.durationMs; |
| 177 | pw.println(String.format("%tT.%tL: %s", localCreationTimeMs, localCreationTimeMs, ev)); |
Hugo Benichi | 64901e5 | 2017-10-19 14:42:40 +0900 | [diff] [blame] | 178 | } |
| 179 | } |