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