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