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.metrics.DefaultNetworkEvent; 21 import android.os.SystemClock; 22 23 import com.android.internal.annotations.GuardedBy; 24 import com.android.internal.util.BitUtils; 25 import com.android.internal.util.RingBuffer; 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 32 /** 33 * Tracks events related to the default network for the purpose of default network metrics. 34 * {@hide} 35 */ 36 public class DefaultNetworkMetrics { 37 38 private static final int ROLLING_LOG_SIZE = 64; 39 40 public final long creationTimeMs = SystemClock.elapsedRealtime(); 41 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<>(); 45 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; 54 // True if the current default network has been validated. 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 DefaultNetworkMetrics()63 public DefaultNetworkMetrics() { 64 newDefaultNetwork(creationTimeMs, null); 65 } 66 listEvents(PrintWriter pw)67 public synchronized void listEvents(PrintWriter pw) { 68 pw.println("default network events:"); 69 long localTimeMs = System.currentTimeMillis(); 70 long timeMs = SystemClock.elapsedRealtime(); 71 for (DefaultNetworkEvent ev : mEventsLog.toArray()) { 72 printEvent(localTimeMs, pw, ev); 73 } 74 mCurrentDefaultNetwork.updateDuration(timeMs); 75 // When printing default network events for bug reports, update validation time 76 // and refresh the last validation timestmap for future validation time updates. 77 if (mIsCurrentlyValid) { 78 updateValidationTime(timeMs); 79 mLastValidationTimeMs = timeMs; 80 } 81 printEvent(localTimeMs, pw, mCurrentDefaultNetwork); 82 } 83 listEventsAsProto(PrintWriter pw)84 public synchronized void listEventsAsProto(PrintWriter pw) { 85 for (DefaultNetworkEvent ev : mEventsLog.toArray()) { 86 pw.print(IpConnectivityEventBuilder.toProto(ev)); 87 } 88 } 89 flushEvents(List<IpConnectivityEvent> out)90 public synchronized void flushEvents(List<IpConnectivityEvent> out) { 91 for (DefaultNetworkEvent ev : mEvents) { 92 out.add(IpConnectivityEventBuilder.toProto(ev)); 93 } 94 mEvents.clear(); 95 } 96 logDefaultNetworkValidity(long timeMs, boolean isValid)97 public synchronized void logDefaultNetworkValidity(long timeMs, boolean isValid) { 98 // Transition from valid to invalid: update validity duration since last update 99 if (!isValid && mIsCurrentlyValid) { 100 mIsCurrentlyValid = false; 101 updateValidationTime(timeMs); 102 } 103 104 // Transition from invalid to valid: simply mark the validation timestamp. 105 if (isValid && !mIsCurrentlyValid) { 106 mIsCurrentlyValid = true; 107 mLastValidationTimeMs = timeMs; 108 } 109 } 110 updateValidationTime(long timeMs)111 private void updateValidationTime(long timeMs) { 112 mCurrentDefaultNetwork.validatedMs += timeMs - mLastValidationTimeMs; 113 } 114 logDefaultNetworkEvent( long timeMs, NetworkAgentInfo newNai, NetworkAgentInfo oldNai)115 public synchronized void logDefaultNetworkEvent( 116 long timeMs, NetworkAgentInfo newNai, NetworkAgentInfo oldNai) { 117 logCurrentDefaultNetwork(timeMs, oldNai); 118 newDefaultNetwork(timeMs, newNai); 119 } 120 logCurrentDefaultNetwork(long timeMs, NetworkAgentInfo oldNai)121 private void logCurrentDefaultNetwork(long timeMs, NetworkAgentInfo oldNai) { 122 if (mIsCurrentlyValid) { 123 updateValidationTime(timeMs); 124 } 125 DefaultNetworkEvent ev = mCurrentDefaultNetwork; 126 ev.updateDuration(timeMs); 127 ev.previousTransports = mLastTransports; 128 // oldNai is null if the system had no default network before the transition. 129 if (oldNai != null) { 130 // The system acquired a new default network. 131 fillLinkInfo(ev, oldNai); 132 ev.finalScore = oldNai.getCurrentScore(); 133 } 134 // Only change transport of the previous default network if the event currently logged 135 // corresponds to an existing default network, and not to the absence of a default network. 136 // This allows to log pairs of transports for successive default networks regardless of 137 // whether or not the system experienced a period without any default network. 138 if (ev.transports != 0) { 139 mLastTransports = ev.transports; 140 } 141 mEvents.add(ev); 142 mEventsLog.append(ev); 143 } 144 newDefaultNetwork(long timeMs, NetworkAgentInfo newNai)145 private void newDefaultNetwork(long timeMs, NetworkAgentInfo newNai) { 146 DefaultNetworkEvent ev = new DefaultNetworkEvent(timeMs); 147 ev.durationMs = timeMs; 148 // newNai is null if the system has no default network after the transition. 149 if (newNai != null) { 150 fillLinkInfo(ev, newNai); 151 ev.initialScore = newNai.getCurrentScore(); 152 if (newNai.lastValidated) { 153 mIsCurrentlyValid = true; 154 mLastValidationTimeMs = timeMs; 155 } 156 } else { 157 mIsCurrentlyValid = false; 158 } 159 mCurrentDefaultNetwork = ev; 160 } 161 fillLinkInfo(DefaultNetworkEvent ev, NetworkAgentInfo nai)162 private static void fillLinkInfo(DefaultNetworkEvent ev, NetworkAgentInfo nai) { 163 LinkProperties lp = nai.linkProperties; 164 ev.netId = nai.network().netId; 165 ev.transports |= BitUtils.packBits(nai.networkCapabilities.getTransportTypes()); 166 ev.ipv4 |= lp.hasIpv4Address() && lp.hasIpv4DefaultRoute(); 167 ev.ipv6 |= lp.hasGlobalIpv6Address() && lp.hasIpv6DefaultRoute(); 168 } 169 printEvent(long localTimeMs, PrintWriter pw, DefaultNetworkEvent ev)170 private static void printEvent(long localTimeMs, PrintWriter pw, DefaultNetworkEvent ev) { 171 long localCreationTimeMs = localTimeMs - ev.durationMs; 172 pw.println(String.format("%tT.%tL: %s", localCreationTimeMs, localCreationTimeMs, ev)); 173 } 174 } 175