summaryrefslogtreecommitdiff
path: root/src/com/android/networkstack/metrics/IpProvisioningMetrics.java
blob: 64e173d284b9455a40fd7d859ce343b3ac229505 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.networkstack.metrics;

import android.net.util.NetworkStackUtils;
import android.net.util.Stopwatch;
import android.stats.connectivity.DhcpErrorCode;
import android.stats.connectivity.DhcpFeature;
import android.stats.connectivity.DisconnectCode;
import android.stats.connectivity.HostnameTransResult;

import java.util.HashSet;
import java.util.Set;

/**
 * Class to record the network IpProvisioning into statsd.
 * 1. Fill in NetworkIpProvisioningReported proto.
 * 2. Write the NetworkIpProvisioningReported proto into statsd.
 * 3. This class is not thread-safe, and should always be accessed from the same thread.
 * @hide
 */

public class IpProvisioningMetrics {
    private static final String TAG = IpProvisioningMetrics.class.getSimpleName();
    private final NetworkIpProvisioningReported.Builder mStatsBuilder =
            NetworkIpProvisioningReported.newBuilder();
    private final DhcpSession.Builder mDhcpSessionBuilder = DhcpSession.newBuilder();
    private final Stopwatch mIpv4Watch = new Stopwatch().start();
    private final Stopwatch mIpv6Watch = new Stopwatch().start();
    private final Stopwatch mWatch = new Stopwatch().start();
    private final Set<DhcpFeature> mDhcpFeatures = new HashSet<DhcpFeature>();

    // Define a maximum number of the DhcpErrorCode.
    public static final int MAX_DHCP_ERROR_COUNT = 20;

    /**
     *  reset this all metrics members
     */
    public void reset() {
        mStatsBuilder.clear();
        mDhcpSessionBuilder.clear();
        mDhcpFeatures.clear();
        mIpv4Watch.restart();
        mIpv6Watch.restart();
        mWatch.restart();
    }

    /**
     * Write the TransportType into mStatsBuilder.
     * TODO: implement this
     */
    public void setTransportType() {}

    /**
     * Write the IPv4Provisioned latency into mStatsBuilder.
     */
    public void setIPv4ProvisionedLatencyOnFirstTime(final boolean isIpv4Provisioned) {
        if (isIpv4Provisioned && !mStatsBuilder.hasIpv4LatencyMicros()) {
            mStatsBuilder.setIpv4LatencyMicros(NetworkStackUtils.saturatedCast(mIpv4Watch.stop()));
        }
    }

    /**
     * Write the IPv6Provisioned latency into mStatsBuilder.
     */
    public void setIPv6ProvisionedLatencyOnFirstTime(final boolean isIpv6Provisioned) {
        if (isIpv6Provisioned && !mStatsBuilder.hasIpv6LatencyMicros()) {
            mStatsBuilder.setIpv6LatencyMicros(NetworkStackUtils.saturatedCast(mIpv6Watch.stop()));
        }
    }

    /**
     * Write the DhcpFeature proto into mStatsBuilder.
     */
    public void setDhcpEnabledFeature(final DhcpFeature feature) {
        if (feature == DhcpFeature.DF_UNKNOWN) return;
        mDhcpFeatures.add(feature);
    }

    /**
     * Write the DHCPDISCOVER transmission count into DhcpSession.
     */
    public void incrementCountForDiscover() {
        mDhcpSessionBuilder.setDiscoverCount(mDhcpSessionBuilder.getDiscoverCount() + 1);
    }

    /**
     * Write the DHCPREQUEST transmission count into DhcpSession.
     */
    public void incrementCountForRequest() {
        mDhcpSessionBuilder.setRequestCount(mDhcpSessionBuilder.getRequestCount() + 1);
    }

    /**
     * Write the IPv4 address conflict count into DhcpSession.
     */
    public void incrementCountForIpConflict() {
        mDhcpSessionBuilder.setConflictCount(mDhcpSessionBuilder.getConflictCount() + 1);
    }

    /**
     * Write the hostname transliteration result into DhcpSession.
     */
    public void setHostnameTransinfo(final boolean isOptionEnabled, final boolean transSuccess) {
        mDhcpSessionBuilder.setHtResult(!isOptionEnabled ? HostnameTransResult.HTR_DISABLE :
                transSuccess ? HostnameTransResult.HTR_SUCCESS : HostnameTransResult.HTR_FAILURE);
    }

    private static DhcpErrorCode dhcpErrorFromNumberSafe(int number) {
        // See DhcpErrorCode.errorCodeWithOption
        // TODO: add a DhcpErrorCode method to extract the code;
        //       or replace legacy error codes with the new metrics.
        final DhcpErrorCode error = DhcpErrorCode.forNumber(number & 0xFFFF0000);
        if (error == null) return DhcpErrorCode.ET_UNKNOWN;
        return error;
    }

    /**
     * write the DHCP error code into DhcpSession.
     */
    public void addDhcpErrorCode(final int errorCode) {
        if (mDhcpSessionBuilder.getErrorCodeCount() >= MAX_DHCP_ERROR_COUNT) return;
        mDhcpSessionBuilder.addErrorCode(dhcpErrorFromNumberSafe(errorCode));
    }

    /**
     * Write the IP provision disconnect code into DhcpSession.
     */
    public void setDisconnectCode(final DisconnectCode disconnectCode) {
        if (mStatsBuilder.hasDisconnectCode()) return;
        mStatsBuilder.setDisconnectCode(disconnectCode);
    }

    /**
     * Write the NetworkIpProvisioningReported proto into statsd.
     */
    public NetworkIpProvisioningReported statsWrite() {
        if (!mWatch.isStarted()) return null;
        for (DhcpFeature feature : mDhcpFeatures) {
            mDhcpSessionBuilder.addUsedFeatures(feature);
        }
        mStatsBuilder.setDhcpSession(mDhcpSessionBuilder);
        mStatsBuilder.setProvisioningDurationMicros(mWatch.stop());
        mStatsBuilder.setRandomNumber((int) (Math.random() * 1000));
        final NetworkIpProvisioningReported Stats = mStatsBuilder.build();
        final byte[] DhcpSession = Stats.getDhcpSession().toByteArray();
        NetworkStackStatsLog.write(NetworkStackStatsLog.NETWORK_IP_PROVISIONING_REPORTED,
                Stats.getTransportType().getNumber(),
                Stats.getIpv4LatencyMicros(),
                Stats.getIpv6LatencyMicros(),
                Stats.getProvisioningDurationMicros(),
                Stats.getDisconnectCode().getNumber(),
                DhcpSession,
                Stats.getRandomNumber());
        mWatch.reset();
        return Stats;
    }
}