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 android.net.metrics; 18 19 import android.net.NetworkCapabilities; 20 21 import com.android.internal.util.BitUtils; 22 23 import java.util.Arrays; 24 25 /** 26 * A batch of DNS events recorded by NetdEventListenerService for a specific network. 27 * {@hide} 28 */ 29 final public class DnsEvent { 30 31 private static final int SIZE_LIMIT = 20000; 32 33 // Network id of the network associated with the event, or 0 if unspecified. 34 public final int netId; 35 // Transports of the network associated with the event, as defined in NetworkCapabilities. 36 // It is the caller responsability to ensure the value of transports does not change between 37 // calls to addResult. 38 public final long transports; 39 // The number of DNS queries recorded. Queries are stored in the structure-of-array style where 40 // the eventTypes, returnCodes, and latenciesMs arrays have the same length and the i-th event 41 // is spread across the three array at position i. 42 public int eventCount; 43 // The number of successful DNS queries recorded. 44 public int successCount; 45 // The types of DNS queries as defined in INetdEventListener. 46 public byte[] eventTypes; 47 // Current getaddrinfo codes go from 1 to EAI_MAX = 15. gethostbyname returns errno, but there 48 // are fewer than 255 errno values. So we store the result code in a byte as well. 49 public byte[] returnCodes; 50 // Latencies in milliseconds of queries, stored as ints. 51 public int[] latenciesMs; 52 DnsEvent(int netId, long transports, int initialCapacity)53 public DnsEvent(int netId, long transports, int initialCapacity) { 54 this.netId = netId; 55 this.transports = transports; 56 eventTypes = new byte[initialCapacity]; 57 returnCodes = new byte[initialCapacity]; 58 latenciesMs = new int[initialCapacity]; 59 } 60 addResult(byte eventType, byte returnCode, int latencyMs)61 boolean addResult(byte eventType, byte returnCode, int latencyMs) { 62 boolean isSuccess = (returnCode == 0); 63 if (eventCount >= SIZE_LIMIT) { 64 // TODO: implement better rate limiting that does not biases metrics. 65 return isSuccess; 66 } 67 if (eventCount == eventTypes.length) { 68 resize((int) (1.4 * eventCount)); 69 } 70 eventTypes[eventCount] = eventType; 71 returnCodes[eventCount] = returnCode; 72 latenciesMs[eventCount] = latencyMs; 73 eventCount++; 74 if (isSuccess) { 75 successCount++; 76 } 77 return isSuccess; 78 } 79 resize(int newLength)80 public void resize(int newLength) { 81 eventTypes = Arrays.copyOf(eventTypes, newLength); 82 returnCodes = Arrays.copyOf(returnCodes, newLength); 83 latenciesMs = Arrays.copyOf(latenciesMs, newLength); 84 } 85 86 @Override toString()87 public String toString() { 88 StringBuilder builder = 89 new StringBuilder("DnsEvent(").append("netId=").append(netId).append(", "); 90 for (int t : BitUtils.unpackBits(transports)) { 91 builder.append(NetworkCapabilities.transportNameOf(t)).append(", "); 92 } 93 builder.append(String.format("%d events, ", eventCount)); 94 builder.append(String.format("%d success)", successCount)); 95 return builder.toString(); 96 } 97 } 98