• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.networkstack.metrics;
18 
19 import android.net.util.Stopwatch;
20 import android.stats.connectivity.DhcpErrorCode;
21 import android.stats.connectivity.DhcpFeature;
22 import android.stats.connectivity.DisconnectCode;
23 import android.stats.connectivity.HostnameTransResult;
24 
25 import com.android.net.module.util.ConnectivityUtils;
26 
27 import java.util.HashSet;
28 import java.util.Set;
29 
30 /**
31  * Class to record the network IpProvisioning into statsd.
32  * 1. Fill in NetworkIpProvisioningReported proto.
33  * 2. Write the NetworkIpProvisioningReported proto into statsd.
34  * 3. This class is not thread-safe, and should always be accessed from the same thread.
35  * @hide
36  */
37 
38 public class IpProvisioningMetrics {
39     private static final String TAG = IpProvisioningMetrics.class.getSimpleName();
40     private final NetworkIpProvisioningReported.Builder mStatsBuilder =
41             NetworkIpProvisioningReported.newBuilder();
42     private final DhcpSession.Builder mDhcpSessionBuilder = DhcpSession.newBuilder();
43     private final Stopwatch mIpv4Watch = new Stopwatch().start();
44     private final Stopwatch mIpv6Watch = new Stopwatch().start();
45     private final Stopwatch mWatch = new Stopwatch().start();
46     private final Set<DhcpFeature> mDhcpFeatures = new HashSet<DhcpFeature>();
47 
48     // Define a maximum number of the DhcpErrorCode.
49     public static final int MAX_DHCP_ERROR_COUNT = 20;
50 
51     /**
52      *  reset this all metrics members
53      */
reset()54     public void reset() {
55         mStatsBuilder.clear();
56         mDhcpSessionBuilder.clear();
57         mDhcpFeatures.clear();
58         mIpv4Watch.restart();
59         mIpv6Watch.restart();
60         mWatch.restart();
61     }
62 
63     /**
64      * Write the TransportType into mStatsBuilder.
65      * TODO: implement this
66      */
setTransportType()67     public void setTransportType() {}
68 
69     /**
70      * Write the IPv4Provisioned latency into mStatsBuilder.
71      */
setIPv4ProvisionedLatencyOnFirstTime(final boolean isIpv4Provisioned)72     public void setIPv4ProvisionedLatencyOnFirstTime(final boolean isIpv4Provisioned) {
73         if (isIpv4Provisioned && !mStatsBuilder.hasIpv4LatencyMicros()) {
74             mStatsBuilder.setIpv4LatencyMicros(ConnectivityUtils.saturatedCast(mIpv4Watch.stop()));
75         }
76     }
77 
78     /**
79      * Write the IPv6Provisioned latency into mStatsBuilder.
80      */
setIPv6ProvisionedLatencyOnFirstTime(final boolean isIpv6Provisioned)81     public void setIPv6ProvisionedLatencyOnFirstTime(final boolean isIpv6Provisioned) {
82         if (isIpv6Provisioned && !mStatsBuilder.hasIpv6LatencyMicros()) {
83             mStatsBuilder.setIpv6LatencyMicros(ConnectivityUtils.saturatedCast(mIpv6Watch.stop()));
84         }
85     }
86 
87     /**
88      * Write the DhcpFeature proto into mStatsBuilder.
89      */
setDhcpEnabledFeature(final DhcpFeature feature)90     public void setDhcpEnabledFeature(final DhcpFeature feature) {
91         if (feature == DhcpFeature.DF_UNKNOWN) return;
92         mDhcpFeatures.add(feature);
93     }
94 
95     /**
96      * Write the DHCPDISCOVER transmission count into DhcpSession.
97      */
incrementCountForDiscover()98     public void incrementCountForDiscover() {
99         mDhcpSessionBuilder.setDiscoverCount(mDhcpSessionBuilder.getDiscoverCount() + 1);
100     }
101 
102     /**
103      * Write the DHCPREQUEST transmission count into DhcpSession.
104      */
incrementCountForRequest()105     public void incrementCountForRequest() {
106         mDhcpSessionBuilder.setRequestCount(mDhcpSessionBuilder.getRequestCount() + 1);
107     }
108 
109     /**
110      * Write the IPv4 address conflict count into DhcpSession.
111      */
incrementCountForIpConflict()112     public void incrementCountForIpConflict() {
113         mDhcpSessionBuilder.setConflictCount(mDhcpSessionBuilder.getConflictCount() + 1);
114     }
115 
116     /**
117      * Write the hostname transliteration result into DhcpSession.
118      */
setHostnameTransinfo(final boolean isOptionEnabled, final boolean transSuccess)119     public void setHostnameTransinfo(final boolean isOptionEnabled, final boolean transSuccess) {
120         mDhcpSessionBuilder.setHtResult(!isOptionEnabled ? HostnameTransResult.HTR_DISABLE :
121                 transSuccess ? HostnameTransResult.HTR_SUCCESS : HostnameTransResult.HTR_FAILURE);
122     }
123 
dhcpErrorFromNumberSafe(int number)124     private static DhcpErrorCode dhcpErrorFromNumberSafe(int number) {
125         // See DhcpErrorCode.errorCodeWithOption
126         // TODO: add a DhcpErrorCode method to extract the code;
127         //       or replace legacy error codes with the new metrics.
128         final DhcpErrorCode error = DhcpErrorCode.forNumber(number & 0xFFFF0000);
129         if (error == null) return DhcpErrorCode.ET_UNKNOWN;
130         return error;
131     }
132 
133     /**
134      * write the DHCP error code into DhcpSession.
135      */
addDhcpErrorCode(final int errorCode)136     public void addDhcpErrorCode(final int errorCode) {
137         if (mDhcpSessionBuilder.getErrorCodeCount() >= MAX_DHCP_ERROR_COUNT) return;
138         mDhcpSessionBuilder.addErrorCode(dhcpErrorFromNumberSafe(errorCode));
139     }
140 
141     /**
142      * Write the IP provision disconnect code into DhcpSession.
143      */
setDisconnectCode(final DisconnectCode disconnectCode)144     public void setDisconnectCode(final DisconnectCode disconnectCode) {
145         if (mStatsBuilder.hasDisconnectCode()) return;
146         mStatsBuilder.setDisconnectCode(disconnectCode);
147     }
148 
149     /**
150      * Write the NetworkIpProvisioningReported proto into statsd.
151      */
statsWrite()152     public NetworkIpProvisioningReported statsWrite() {
153         if (!mWatch.isStarted()) return null;
154         for (DhcpFeature feature : mDhcpFeatures) {
155             mDhcpSessionBuilder.addUsedFeatures(feature);
156         }
157         mStatsBuilder.setDhcpSession(mDhcpSessionBuilder);
158         mStatsBuilder.setProvisioningDurationMicros(mWatch.stop());
159         mStatsBuilder.setRandomNumber((int) (Math.random() * 1000));
160         final NetworkIpProvisioningReported Stats = mStatsBuilder.build();
161         final byte[] DhcpSession = Stats.getDhcpSession().toByteArray();
162         NetworkStackStatsLog.write(NetworkStackStatsLog.NETWORK_IP_PROVISIONING_REPORTED,
163                 Stats.getTransportType().getNumber(),
164                 Stats.getIpv4LatencyMicros(),
165                 Stats.getIpv6LatencyMicros(),
166                 Stats.getProvisioningDurationMicros(),
167                 Stats.getDisconnectCode().getNumber(),
168                 DhcpSession,
169                 Stats.getRandomNumber());
170         mWatch.reset();
171         return Stats;
172     }
173 }
174