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