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.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.annotation.TestApi;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.util.SparseArray;
26 
27 import com.android.internal.util.MessageUtils;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 
32 /**
33  * An event recorded by NetworkMonitor when sending a probe for finding captive portals.
34  * {@hide}
35  */
36 @SystemApi
37 @TestApi
38 public final class ValidationProbeEvent implements IpConnectivityLog.Event {
39 
40     public static final int PROBE_DNS       = 0;
41     public static final int PROBE_HTTP      = 1;
42     public static final int PROBE_HTTPS     = 2;
43     public static final int PROBE_PAC       = 3;
44     public static final int PROBE_FALLBACK  = 4;
45     public static final int PROBE_PRIVDNS   = 5;
46 
47     public static final int DNS_FAILURE = 0;
48     public static final int DNS_SUCCESS = 1;
49 
50     private static final int FIRST_VALIDATION  = 1 << 8;
51     private static final int REVALIDATION      = 2 << 8;
52 
53     /** @hide */
54     @IntDef(value = {DNS_FAILURE, DNS_SUCCESS})
55     @Retention(RetentionPolicy.SOURCE)
56     public @interface ReturnCode {}
57 
58     /** @hide */
59     public final long durationMs;
60     // probeType byte format (MSB to LSB):
61     // byte 0: unused
62     // byte 1: unused
63     // byte 2: 0 = UNKNOWN, 1 = FIRST_VALIDATION, 2 = REVALIDATION
64     // byte 3: PROBE_* constant
65     /** @hide */
66     public final int probeType;
67     /** @hide */
68     public final @ReturnCode int returnCode;
69 
ValidationProbeEvent(long durationMs, int probeType, int returnCode)70     private ValidationProbeEvent(long durationMs, int probeType, int returnCode) {
71         this.durationMs = durationMs;
72         this.probeType = probeType;
73         this.returnCode = returnCode;
74     }
75 
ValidationProbeEvent(Parcel in)76     private ValidationProbeEvent(Parcel in) {
77         durationMs = in.readLong();
78         probeType = in.readInt();
79         returnCode = in.readInt();
80     }
81 
82     /**
83      * Utility to create an instance of {@link ValidationProbeEvent}.
84      */
85     public static final class Builder {
86         private long mDurationMs;
87         private int mProbeType;
88         private int mReturnCode;
89 
90         /**
91          * Set the duration of the probe in milliseconds.
92          */
93         @NonNull
setDurationMs(long durationMs)94         public Builder setDurationMs(long durationMs) {
95             mDurationMs = durationMs;
96             return this;
97         }
98 
99         /**
100          * Set the probe type based on whether it was the first validation.
101          */
102         @NonNull
setProbeType(int probeType, boolean firstValidation)103         public Builder setProbeType(int probeType, boolean firstValidation) {
104             mProbeType = makeProbeType(probeType, firstValidation);
105             return this;
106         }
107 
108         /**
109          * Set the return code of the probe.
110          */
111         @NonNull
setReturnCode(int returnCode)112         public Builder setReturnCode(int returnCode) {
113             mReturnCode = returnCode;
114             return this;
115         }
116 
117         /**
118          * Create a new {@link ValidationProbeEvent}.
119          */
120         @NonNull
build()121         public ValidationProbeEvent build() {
122             return new ValidationProbeEvent(mDurationMs, mProbeType, mReturnCode);
123         }
124     }
125 
126     /** @hide */
127     @Override
writeToParcel(Parcel out, int flags)128     public void writeToParcel(Parcel out, int flags) {
129         out.writeLong(durationMs);
130         out.writeInt(probeType);
131         out.writeInt(returnCode);
132     }
133 
134     /** @hide */
135     @Override
describeContents()136     public int describeContents() {
137         return 0;
138     }
139 
140     /** @hide */
141     public static final @android.annotation.NonNull Parcelable.Creator<ValidationProbeEvent> CREATOR
142         = new Parcelable.Creator<ValidationProbeEvent>() {
143         public ValidationProbeEvent createFromParcel(Parcel in) {
144             return new ValidationProbeEvent(in);
145         }
146 
147         public ValidationProbeEvent[] newArray(int size) {
148             return new ValidationProbeEvent[size];
149         }
150     };
151 
makeProbeType(int probeType, boolean firstValidation)152     private static int makeProbeType(int probeType, boolean firstValidation) {
153         return (probeType & 0xff) | (firstValidation ? FIRST_VALIDATION : REVALIDATION);
154     }
155 
156     /**
157      * Get the name of a probe specified by its probe type.
158      */
getProbeName(int probeType)159     public static @NonNull String getProbeName(int probeType) {
160         return Decoder.constants.get(probeType & 0xff, "PROBE_???");
161     }
162 
getValidationStage(int probeType)163     private static @NonNull String getValidationStage(int probeType) {
164         return Decoder.constants.get(probeType & 0xff00, "UNKNOWN");
165     }
166 
167     @Override
toString()168     public String toString() {
169         return String.format("ValidationProbeEvent(%s:%d %s, %dms)",
170                 getProbeName(probeType), returnCode, getValidationStage(probeType), durationMs);
171     }
172 
173     @Override
equals(Object obj)174     public boolean equals(Object obj) {
175         if (obj == null || !(obj.getClass().equals(ValidationProbeEvent.class))) return false;
176         final ValidationProbeEvent other = (ValidationProbeEvent) obj;
177         return durationMs == other.durationMs
178                 && probeType == other.probeType
179                 && returnCode == other.returnCode;
180     }
181 
182     final static class Decoder {
183         static final SparseArray<String> constants = MessageUtils.findMessageNames(
184                 new Class[]{ValidationProbeEvent.class},
185                 new String[]{"PROBE_", "FIRST_", "REVALIDATION"});
186     }
187 }
188