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