blob: 9086d49231bb7512464c7e3ca396ac811ee388a5 [file] [log] [blame]
Cody Kesting9a80eaf2019-12-11 08:34:51 -08001/*
2 * Copyright (C) 2019 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
17package android.net;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
Cody Kesting73328662019-12-17 08:51:32 -080021import android.annotation.Nullable;
Cody Kestingc14f4532020-01-20 18:03:41 -080022import android.annotation.StringDef;
Cody Kestingb125776002019-12-17 17:21:40 -080023import android.content.Context;
Cody Kesting8a5f7c92019-12-17 16:46:11 -080024import android.os.Binder;
Cody Kesting73328662019-12-17 08:51:32 -080025import android.os.Parcel;
26import android.os.Parcelable;
Cody Kesting9a80eaf2019-12-11 08:34:51 -080027import android.os.PersistableBundle;
Cody Kesting63e4e002019-12-18 10:57:50 -080028import android.os.RemoteException;
Cody Kesting9a80eaf2019-12-11 08:34:51 -080029
Cody Kesting73328662019-12-17 08:51:32 -080030import com.android.internal.annotations.VisibleForTesting;
Cody Kestingb125776002019-12-17 17:21:40 -080031import com.android.internal.util.Preconditions;
Cody Kesting73328662019-12-17 08:51:32 -080032
Cody Kesting9a80eaf2019-12-11 08:34:51 -080033import java.lang.annotation.Retention;
34import java.lang.annotation.RetentionPolicy;
Cody Kesting63e4e002019-12-18 10:57:50 -080035import java.util.Map;
Cody Kesting73328662019-12-17 08:51:32 -080036import java.util.Objects;
Cody Kesting63e4e002019-12-18 10:57:50 -080037import java.util.concurrent.ConcurrentHashMap;
Cody Kesting9a80eaf2019-12-11 08:34:51 -080038import java.util.concurrent.Executor;
39
40/**
41 * Class that provides utilities for collecting network connectivity diagnostics information.
42 * Connectivity information is made available through triggerable diagnostics tools and by listening
43 * to System validations. Some diagnostics information may be permissions-restricted.
44 *
45 * <p>ConnectivityDiagnosticsManager is intended for use by applications offering network
46 * connectivity on a user device. These tools will provide several mechanisms for these applications
47 * to be alerted to network conditions as well as diagnose potential network issues themselves.
48 *
49 * <p>The primary responsibilities of this class are to:
50 *
51 * <ul>
52 * <li>Allow permissioned applications to register and unregister callbacks for network event
53 * notifications
54 * <li>Invoke callbacks for network event notifications, including:
55 * <ul>
56 * <li>Network validations
57 * <li>Data stalls
58 * <li>Connectivity reports from applications
59 * </ul>
60 * </ul>
61 */
62public class ConnectivityDiagnosticsManager {
Cody Kesting63e4e002019-12-18 10:57:50 -080063 /** @hide */
64 @VisibleForTesting
65 public static final Map<ConnectivityDiagnosticsCallback, ConnectivityDiagnosticsBinder>
66 sCallbacks = new ConcurrentHashMap<>();
67
Cody Kestingb125776002019-12-17 17:21:40 -080068 private final Context mContext;
69 private final IConnectivityManager mService;
70
Cody Kesting9a80eaf2019-12-11 08:34:51 -080071 /** @hide */
Cody Kestingb125776002019-12-17 17:21:40 -080072 public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) {
73 mContext = Preconditions.checkNotNull(context, "missing context");
74 mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
75 }
Cody Kesting9a80eaf2019-12-11 08:34:51 -080076
Cody Kesting73328662019-12-17 08:51:32 -080077 /** @hide */
78 @VisibleForTesting
79 public static boolean persistableBundleEquals(
80 @Nullable PersistableBundle a, @Nullable PersistableBundle b) {
81 if (a == b) return true;
82 if (a == null || b == null) return false;
83 if (!Objects.equals(a.keySet(), b.keySet())) return false;
84 for (String key : a.keySet()) {
85 if (!Objects.equals(a.get(key), b.get(key))) return false;
86 }
87 return true;
88 }
89
Cody Kesting9a80eaf2019-12-11 08:34:51 -080090 /** Class that includes connectivity information for a specific Network at a specific time. */
Cody Kesting73328662019-12-17 08:51:32 -080091 public static final class ConnectivityReport implements Parcelable {
Cody Kestingc14f4532020-01-20 18:03:41 -080092 /**
93 * The overall status of the network is that it is invalid; it neither provides
94 * connectivity nor has been exempted from validation.
95 */
96 public static final int NETWORK_VALIDATION_RESULT_INVALID = 0;
97
98 /**
99 * The overall status of the network is that it is valid, this may be because it provides
100 * full Internet access (all probes succeeded), or because other properties of the network
101 * caused probes not to be run.
102 */
103 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID
104 public static final int NETWORK_VALIDATION_RESULT_VALID = 1;
105
106 /**
107 * The overall status of the network is that it provides partial connectivity; some
108 * probed services succeeded but others failed.
109 */
110 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
111 public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2;
112
113 /**
114 * Due to the properties of the network, validation was not performed.
115 */
116 public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3;
117
118 /** @hide */
119 @IntDef(
120 prefix = {"NETWORK_VALIDATION_RESULT_"},
121 value = {
122 NETWORK_VALIDATION_RESULT_INVALID,
123 NETWORK_VALIDATION_RESULT_VALID,
124 NETWORK_VALIDATION_RESULT_PARTIALLY_VALID,
125 NETWORK_VALIDATION_RESULT_SKIPPED
126 })
127 @Retention(RetentionPolicy.SOURCE)
128 public @interface NetworkValidationResult {}
129
130 /**
131 * The overall validation result for the Network being reported on.
132 *
133 * <p>The possible values for this key are:
134 * {@link #NETWORK_VALIDATION_RESULT_INVALID},
135 * {@link #NETWORK_VALIDATION_RESULT_VALID},
136 * {@link #NETWORK_VALIDATION_RESULT_PARTIALLY_VALID},
137 * {@link #NETWORK_VALIDATION_RESULT_SKIPPED}.
138 *
Automerger Merge Workerfcfddef2020-03-16 20:31:58 +0000139 * @see android.net.NetworkCapabilities#NET_CAPABILITY_VALIDATED
Cody Kestingc14f4532020-01-20 18:03:41 -0800140 */
141 @NetworkValidationResult
142 public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
143
144 /** DNS probe. */
145 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS
146 public static final int NETWORK_PROBE_DNS = 0x04;
147
148 /** HTTP probe. */
149 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP
150 public static final int NETWORK_PROBE_HTTP = 0x08;
151
152 /** HTTPS probe. */
153 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
154 public static final int NETWORK_PROBE_HTTPS = 0x10;
155
156 /** Captive portal fallback probe. */
157 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_FALLBACK
158 public static final int NETWORK_PROBE_FALLBACK = 0x20;
159
160 /** Private DNS (DNS over TLS) probd. */
161 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS
162 public static final int NETWORK_PROBE_PRIVATE_DNS = 0x40;
163
164 /** @hide */
165 @IntDef(
166 prefix = {"NETWORK_PROBE_"},
167 value = {
168 NETWORK_PROBE_DNS,
169 NETWORK_PROBE_HTTP,
170 NETWORK_PROBE_HTTPS,
171 NETWORK_PROBE_FALLBACK,
172 NETWORK_PROBE_PRIVATE_DNS
173 })
174 @Retention(RetentionPolicy.SOURCE)
175 public @interface NetworkProbe {}
176
177 /**
178 * A bitmask of network validation probes that succeeded.
179 *
180 * <p>The possible bits values reported by this key are:
181 * {@link #NETWORK_PROBE_DNS},
182 * {@link #NETWORK_PROBE_HTTP},
183 * {@link #NETWORK_PROBE_HTTPS},
184 * {@link #NETWORK_PROBE_FALLBACK},
185 * {@link #NETWORK_PROBE_PRIVATE_DNS}.
186 */
187 @NetworkProbe
188 public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK =
189 "networkProbesSucceeded";
190
191 /**
192 * A bitmask of network validation probes that were attempted.
193 *
194 * <p>These probes may have failed or may be incomplete at the time of this report.
195 *
196 * <p>The possible bits values reported by this key are:
197 * {@link #NETWORK_PROBE_DNS},
198 * {@link #NETWORK_PROBE_HTTP},
199 * {@link #NETWORK_PROBE_HTTPS},
200 * {@link #NETWORK_PROBE_FALLBACK},
201 * {@link #NETWORK_PROBE_PRIVATE_DNS}.
202 */
203 @NetworkProbe
204 public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK =
Cody Kesting5c3e7d52020-02-05 08:53:03 -0800205 "networkProbesAttempted";
Cody Kestingc14f4532020-01-20 18:03:41 -0800206
207 /** @hide */
208 @StringDef(prefix = {"KEY_"}, value = {
209 KEY_NETWORK_VALIDATION_RESULT, KEY_NETWORK_PROBES_SUCCEEDED_BITMASK,
210 KEY_NETWORK_PROBES_ATTEMPTED_BITMASK})
211 @Retention(RetentionPolicy.SOURCE)
212 public @interface ConnectivityReportBundleKeys {}
213
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800214 /** The Network for which this ConnectivityReport applied */
Cody Kesting73328662019-12-17 08:51:32 -0800215 @NonNull private final Network mNetwork;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800216
217 /**
218 * The timestamp for the report. The timestamp is taken from {@link
219 * System#currentTimeMillis}.
220 */
Cody Kesting73328662019-12-17 08:51:32 -0800221 private final long mReportTimestamp;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800222
223 /** LinkProperties available on the Network at the reported timestamp */
Cody Kesting73328662019-12-17 08:51:32 -0800224 @NonNull private final LinkProperties mLinkProperties;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800225
226 /** NetworkCapabilities available on the Network at the reported timestamp */
Cody Kesting73328662019-12-17 08:51:32 -0800227 @NonNull private final NetworkCapabilities mNetworkCapabilities;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800228
229 /** PersistableBundle that may contain additional info about the report */
Cody Kesting73328662019-12-17 08:51:32 -0800230 @NonNull private final PersistableBundle mAdditionalInfo;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800231
232 /**
233 * Constructor for ConnectivityReport.
234 *
235 * <p>Apps should obtain instances through {@link
Cody Kesting9347e332020-03-05 15:19:48 -0800236 * ConnectivityDiagnosticsCallback#onConnectivityReportAvailable} instead of instantiating
237 * their own instances (unless for testing purposes).
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800238 *
239 * @param network The Network for which this ConnectivityReport applies
240 * @param reportTimestamp The timestamp for the report
241 * @param linkProperties The LinkProperties available on network at reportTimestamp
242 * @param networkCapabilities The NetworkCapabilities available on network at
243 * reportTimestamp
244 * @param additionalInfo A PersistableBundle that may contain additional info about the
245 * report
246 */
247 public ConnectivityReport(
248 @NonNull Network network,
249 long reportTimestamp,
250 @NonNull LinkProperties linkProperties,
251 @NonNull NetworkCapabilities networkCapabilities,
252 @NonNull PersistableBundle additionalInfo) {
Cody Kesting73328662019-12-17 08:51:32 -0800253 mNetwork = network;
254 mReportTimestamp = reportTimestamp;
Cody Kesting7064b5c2020-02-04 21:52:09 -0800255 mLinkProperties = new LinkProperties(linkProperties);
256 mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
Cody Kesting73328662019-12-17 08:51:32 -0800257 mAdditionalInfo = additionalInfo;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800258 }
Cody Kesting73328662019-12-17 08:51:32 -0800259
260 /**
261 * Returns the Network for this ConnectivityReport.
262 *
263 * @return The Network for which this ConnectivityReport applied
264 */
265 @NonNull
266 public Network getNetwork() {
267 return mNetwork;
268 }
269
270 /**
271 * Returns the epoch timestamp (milliseconds) for when this report was taken.
272 *
273 * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
274 */
275 public long getReportTimestamp() {
276 return mReportTimestamp;
277 }
278
279 /**
280 * Returns the LinkProperties available when this report was taken.
281 *
282 * @return LinkProperties available on the Network at the reported timestamp
283 */
284 @NonNull
285 public LinkProperties getLinkProperties() {
286 return new LinkProperties(mLinkProperties);
287 }
288
289 /**
290 * Returns the NetworkCapabilities when this report was taken.
291 *
292 * @return NetworkCapabilities available on the Network at the reported timestamp
293 */
294 @NonNull
295 public NetworkCapabilities getNetworkCapabilities() {
296 return new NetworkCapabilities(mNetworkCapabilities);
297 }
298
299 /**
300 * Returns a PersistableBundle with additional info for this report.
301 *
302 * @return PersistableBundle that may contain additional info about the report
303 */
304 @NonNull
305 public PersistableBundle getAdditionalInfo() {
306 return new PersistableBundle(mAdditionalInfo);
307 }
308
309 @Override
310 public boolean equals(@Nullable Object o) {
311 if (this == o) return true;
312 if (!(o instanceof ConnectivityReport)) return false;
313 final ConnectivityReport that = (ConnectivityReport) o;
314
315 // PersistableBundle is optimized to avoid unparcelling data unless fields are
316 // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
317 // {@link PersistableBundle#kindofEquals}.
318 return mReportTimestamp == that.mReportTimestamp
319 && mNetwork.equals(that.mNetwork)
320 && mLinkProperties.equals(that.mLinkProperties)
321 && mNetworkCapabilities.equals(that.mNetworkCapabilities)
322 && persistableBundleEquals(mAdditionalInfo, that.mAdditionalInfo);
323 }
324
325 @Override
326 public int hashCode() {
327 return Objects.hash(
328 mNetwork,
329 mReportTimestamp,
330 mLinkProperties,
331 mNetworkCapabilities,
332 mAdditionalInfo);
333 }
334
335 /** {@inheritDoc} */
336 @Override
337 public int describeContents() {
338 return 0;
339 }
340
341 /** {@inheritDoc} */
342 @Override
343 public void writeToParcel(@NonNull Parcel dest, int flags) {
344 dest.writeParcelable(mNetwork, flags);
345 dest.writeLong(mReportTimestamp);
346 dest.writeParcelable(mLinkProperties, flags);
347 dest.writeParcelable(mNetworkCapabilities, flags);
348 dest.writeParcelable(mAdditionalInfo, flags);
349 }
350
351 /** Implement the Parcelable interface */
352 public static final @NonNull Creator<ConnectivityReport> CREATOR =
Cody Kestingef028212020-01-22 20:14:48 -0800353 new Creator<ConnectivityReport>() {
Cody Kesting73328662019-12-17 08:51:32 -0800354 public ConnectivityReport createFromParcel(Parcel in) {
355 return new ConnectivityReport(
356 in.readParcelable(null),
357 in.readLong(),
358 in.readParcelable(null),
359 in.readParcelable(null),
360 in.readParcelable(null));
361 }
362
363 public ConnectivityReport[] newArray(int size) {
364 return new ConnectivityReport[size];
365 }
366 };
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800367 }
368
369 /** Class that includes information for a suspected data stall on a specific Network */
Cody Kestingfc199ca2019-12-17 09:28:06 -0800370 public static final class DataStallReport implements Parcelable {
Automerger Merge Worker5b6688c2020-03-13 20:51:48 +0000371 /**
372 * Indicates that the Data Stall was detected using DNS events.
373 */
Cody Kestingfc199ca2019-12-17 09:28:06 -0800374 public static final int DETECTION_METHOD_DNS_EVENTS = 1;
Automerger Merge Worker5b6688c2020-03-13 20:51:48 +0000375
376 /**
377 * Indicates that the Data Stall was detected using TCP metrics.
378 */
Cody Kestingfc199ca2019-12-17 09:28:06 -0800379 public static final int DETECTION_METHOD_TCP_METRICS = 2;
380
381 /** @hide */
382 @Retention(RetentionPolicy.SOURCE)
383 @IntDef(
384 prefix = {"DETECTION_METHOD_"},
385 value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
386 public @interface DetectionMethod {}
387
Cody Kestingc14f4532020-01-20 18:03:41 -0800388 /**
389 * This key represents the period in milliseconds over which other included TCP metrics
390 * were measured.
391 *
392 * <p>This key will be included if the data stall detection method is
393 * {@link #DETECTION_METHOD_TCP_METRICS}.
394 *
395 * <p>This value is an int.
396 */
397 public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS =
398 "tcpMetricsCollectionPeriodMillis";
399
400 /**
401 * This key represents the fail rate of TCP packets when the suspected data stall was
402 * detected.
403 *
404 * <p>This key will be included if the data stall detection method is
405 * {@link #DETECTION_METHOD_TCP_METRICS}.
406 *
407 * <p>This value is an int percentage between 0 and 100.
408 */
409 public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
410
411 /**
412 * This key represents the consecutive number of DNS timeouts that have occurred.
413 *
414 * <p>The consecutive count will be reset any time a DNS response is received.
415 *
416 * <p>This key will be included if the data stall detection method is
417 * {@link #DETECTION_METHOD_DNS_EVENTS}.
418 *
419 * <p>This value is an int.
420 */
421 public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
422
423 /** @hide */
424 @Retention(RetentionPolicy.SOURCE)
425 @StringDef(prefix = {"KEY_"}, value = {
426 KEY_TCP_PACKET_FAIL_RATE,
427 KEY_DNS_CONSECUTIVE_TIMEOUTS
428 })
429 public @interface DataStallReportBundleKeys {}
430
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800431 /** The Network for which this DataStallReport applied */
Cody Kestingfc199ca2019-12-17 09:28:06 -0800432 @NonNull private final Network mNetwork;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800433
434 /**
435 * The timestamp for the report. The timestamp is taken from {@link
436 * System#currentTimeMillis}.
437 */
Cody Kestingfc199ca2019-12-17 09:28:06 -0800438 private long mReportTimestamp;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800439
440 /** The detection method used to identify the suspected data stall */
Cody Kestingfc199ca2019-12-17 09:28:06 -0800441 @DetectionMethod private final int mDetectionMethod;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800442
Cody Kesting7064b5c2020-02-04 21:52:09 -0800443 /** LinkProperties available on the Network at the reported timestamp */
444 @NonNull private final LinkProperties mLinkProperties;
445
446 /** NetworkCapabilities available on the Network at the reported timestamp */
447 @NonNull private final NetworkCapabilities mNetworkCapabilities;
448
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800449 /** PersistableBundle that may contain additional information on the suspected data stall */
Cody Kestingfc199ca2019-12-17 09:28:06 -0800450 @NonNull private final PersistableBundle mStallDetails;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800451
452 /**
453 * Constructor for DataStallReport.
454 *
455 * <p>Apps should obtain instances through {@link
456 * ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own
457 * instances (unless for testing purposes).
458 *
459 * @param network The Network for which this DataStallReport applies
460 * @param reportTimestamp The timestamp for the report
461 * @param detectionMethod The detection method used to identify this data stall
Cody Kesting7064b5c2020-02-04 21:52:09 -0800462 * @param linkProperties The LinkProperties available on network at reportTimestamp
463 * @param networkCapabilities The NetworkCapabilities available on network at
464 * reportTimestamp
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800465 * @param stallDetails A PersistableBundle that may contain additional info about the report
466 */
467 public DataStallReport(
468 @NonNull Network network,
469 long reportTimestamp,
470 @DetectionMethod int detectionMethod,
Cody Kesting7064b5c2020-02-04 21:52:09 -0800471 @NonNull LinkProperties linkProperties,
472 @NonNull NetworkCapabilities networkCapabilities,
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800473 @NonNull PersistableBundle stallDetails) {
Cody Kestingfc199ca2019-12-17 09:28:06 -0800474 mNetwork = network;
475 mReportTimestamp = reportTimestamp;
476 mDetectionMethod = detectionMethod;
Cody Kesting7064b5c2020-02-04 21:52:09 -0800477 mLinkProperties = new LinkProperties(linkProperties);
478 mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
Cody Kestingfc199ca2019-12-17 09:28:06 -0800479 mStallDetails = stallDetails;
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800480 }
Cody Kestingfc199ca2019-12-17 09:28:06 -0800481
482 /**
483 * Returns the Network for this DataStallReport.
484 *
485 * @return The Network for which this DataStallReport applied
486 */
487 @NonNull
488 public Network getNetwork() {
489 return mNetwork;
490 }
491
492 /**
493 * Returns the epoch timestamp (milliseconds) for when this report was taken.
494 *
495 * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
496 */
497 public long getReportTimestamp() {
498 return mReportTimestamp;
499 }
500
501 /**
502 * Returns the detection method used to identify this suspected data stall.
503 *
504 * @return The detection method used to identify the suspected data stall
505 */
506 public int getDetectionMethod() {
507 return mDetectionMethod;
508 }
509
510 /**
Cody Kesting7064b5c2020-02-04 21:52:09 -0800511 * Returns the LinkProperties available when this report was taken.
512 *
513 * @return LinkProperties available on the Network at the reported timestamp
514 */
515 @NonNull
516 public LinkProperties getLinkProperties() {
517 return new LinkProperties(mLinkProperties);
518 }
519
520 /**
521 * Returns the NetworkCapabilities when this report was taken.
522 *
523 * @return NetworkCapabilities available on the Network at the reported timestamp
524 */
525 @NonNull
526 public NetworkCapabilities getNetworkCapabilities() {
527 return new NetworkCapabilities(mNetworkCapabilities);
528 }
529
530 /**
Cody Kestingfc199ca2019-12-17 09:28:06 -0800531 * Returns a PersistableBundle with additional info for this report.
532 *
Cody Kestingc14f4532020-01-20 18:03:41 -0800533 * <p>Gets a bundle with details about the suspected data stall including information
534 * specific to the monitoring method that detected the data stall.
535 *
Cody Kestingfc199ca2019-12-17 09:28:06 -0800536 * @return PersistableBundle that may contain additional information on the suspected data
537 * stall
538 */
539 @NonNull
540 public PersistableBundle getStallDetails() {
541 return new PersistableBundle(mStallDetails);
542 }
543
544 @Override
545 public boolean equals(@Nullable Object o) {
546 if (this == o) return true;
547 if (!(o instanceof DataStallReport)) return false;
548 final DataStallReport that = (DataStallReport) o;
549
550 // PersistableBundle is optimized to avoid unparcelling data unless fields are
551 // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
552 // {@link PersistableBundle#kindofEquals}.
553 return mReportTimestamp == that.mReportTimestamp
554 && mDetectionMethod == that.mDetectionMethod
555 && mNetwork.equals(that.mNetwork)
Cody Kesting7064b5c2020-02-04 21:52:09 -0800556 && mLinkProperties.equals(that.mLinkProperties)
557 && mNetworkCapabilities.equals(that.mNetworkCapabilities)
Cody Kestingfc199ca2019-12-17 09:28:06 -0800558 && persistableBundleEquals(mStallDetails, that.mStallDetails);
559 }
560
561 @Override
562 public int hashCode() {
Cody Kesting7064b5c2020-02-04 21:52:09 -0800563 return Objects.hash(
564 mNetwork,
565 mReportTimestamp,
566 mDetectionMethod,
567 mLinkProperties,
568 mNetworkCapabilities,
569 mStallDetails);
Cody Kestingfc199ca2019-12-17 09:28:06 -0800570 }
571
572 /** {@inheritDoc} */
573 @Override
574 public int describeContents() {
575 return 0;
576 }
577
578 /** {@inheritDoc} */
579 @Override
580 public void writeToParcel(@NonNull Parcel dest, int flags) {
581 dest.writeParcelable(mNetwork, flags);
582 dest.writeLong(mReportTimestamp);
583 dest.writeInt(mDetectionMethod);
Cody Kesting7064b5c2020-02-04 21:52:09 -0800584 dest.writeParcelable(mLinkProperties, flags);
585 dest.writeParcelable(mNetworkCapabilities, flags);
Cody Kestingfc199ca2019-12-17 09:28:06 -0800586 dest.writeParcelable(mStallDetails, flags);
587 }
588
589 /** Implement the Parcelable interface */
590 public static final @NonNull Creator<DataStallReport> CREATOR =
591 new Creator<DataStallReport>() {
592 public DataStallReport createFromParcel(Parcel in) {
593 return new DataStallReport(
594 in.readParcelable(null),
595 in.readLong(),
596 in.readInt(),
Cody Kesting7064b5c2020-02-04 21:52:09 -0800597 in.readParcelable(null),
598 in.readParcelable(null),
Cody Kestingfc199ca2019-12-17 09:28:06 -0800599 in.readParcelable(null));
600 }
601
602 public DataStallReport[] newArray(int size) {
603 return new DataStallReport[size];
604 }
605 };
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800606 }
607
Cody Kesting8a5f7c92019-12-17 16:46:11 -0800608 /** @hide */
609 @VisibleForTesting
610 public static class ConnectivityDiagnosticsBinder
611 extends IConnectivityDiagnosticsCallback.Stub {
612 @NonNull private final ConnectivityDiagnosticsCallback mCb;
613 @NonNull private final Executor mExecutor;
614
615 /** @hide */
616 @VisibleForTesting
617 public ConnectivityDiagnosticsBinder(
618 @NonNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor) {
619 this.mCb = cb;
620 this.mExecutor = executor;
621 }
622
623 /** @hide */
624 @VisibleForTesting
Cody Kesting9347e332020-03-05 15:19:48 -0800625 public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {
Cody Kesting8a5f7c92019-12-17 16:46:11 -0800626 Binder.withCleanCallingIdentity(() -> {
627 mExecutor.execute(() -> {
Cody Kesting9347e332020-03-05 15:19:48 -0800628 mCb.onConnectivityReportAvailable(report);
Cody Kesting8a5f7c92019-12-17 16:46:11 -0800629 });
630 });
631 }
632
633 /** @hide */
634 @VisibleForTesting
635 public void onDataStallSuspected(@NonNull DataStallReport report) {
636 Binder.withCleanCallingIdentity(() -> {
637 mExecutor.execute(() -> {
638 mCb.onDataStallSuspected(report);
639 });
640 });
641 }
642
643 /** @hide */
644 @VisibleForTesting
645 public void onNetworkConnectivityReported(
646 @NonNull Network network, boolean hasConnectivity) {
647 Binder.withCleanCallingIdentity(() -> {
648 mExecutor.execute(() -> {
649 mCb.onNetworkConnectivityReported(network, hasConnectivity);
650 });
651 });
652 }
653 }
654
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800655 /**
656 * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about
657 * network connectivity events. Must be extended by applications wanting notifications.
658 */
659 public abstract static class ConnectivityDiagnosticsCallback {
660 /**
661 * Called when the platform completes a data connectivity check. This will also be invoked
Cody Kesting95a98c22020-03-30 12:03:21 -0700662 * immediately upon registration for each network matching the request with the latest
663 * report, if a report has already been generated for that network.
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800664 *
665 * <p>The Network specified in the ConnectivityReport may not be active any more when this
666 * method is invoked.
667 *
668 * @param report The ConnectivityReport containing information about a connectivity check
669 */
Cody Kesting9347e332020-03-05 15:19:48 -0800670 public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {}
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800671
672 /**
673 * Called when the platform suspects a data stall on some Network.
674 *
675 * <p>The Network specified in the DataStallReport may not be active any more when this
676 * method is invoked.
677 *
678 * @param report The DataStallReport containing information about the suspected data stall
679 */
680 public void onDataStallSuspected(@NonNull DataStallReport report) {}
681
682 /**
683 * Called when any app reports connectivity to the System.
684 *
685 * @param network The Network for which connectivity has been reported
686 * @param hasConnectivity The connectivity reported to the System
687 */
688 public void onNetworkConnectivityReported(
689 @NonNull Network network, boolean hasConnectivity) {}
690 }
691
692 /**
693 * Registers a ConnectivityDiagnosticsCallback with the System.
694 *
Cody Kestingaadf4832019-12-19 12:36:18 -0800695 * <p>Only apps that offer network connectivity to the user should be registering callbacks.
696 * These are the only apps whose callbacks will be invoked by the system. Apps considered to
697 * meet these conditions include:
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800698 *
699 * <ul>
700 * <li>Carrier apps with active subscriptions
701 * <li>Active VPNs
702 * <li>WiFi Suggesters
703 * </ul>
704 *
Cody Kestingaadf4832019-12-19 12:36:18 -0800705 * <p>Callbacks registered by apps not meeting the above criteria will not be invoked.
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800706 *
707 * <p>If a registering app loses its relevant permissions, any callbacks it registered will
708 * silently stop receiving callbacks.
709 *
Cody Kesting63e4e002019-12-18 10:57:50 -0800710 * <p>Each register() call <b>MUST</b> use a ConnectivityDiagnosticsCallback instance that is
711 * not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with
712 * multiple NetworkRequests, an IllegalArgumentException will be thrown.
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800713 *
714 * @param request The NetworkRequest that will be used to match with Networks for which
715 * callbacks will be fired
716 * @param e The Executor to be used for running the callback method invocations
717 * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the
718 * System
719 * @throws IllegalArgumentException if the same callback instance is registered with multiple
720 * NetworkRequests
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800721 */
722 public void registerConnectivityDiagnosticsCallback(
723 @NonNull NetworkRequest request,
724 @NonNull Executor e,
725 @NonNull ConnectivityDiagnosticsCallback callback) {
Cody Kesting63e4e002019-12-18 10:57:50 -0800726 final ConnectivityDiagnosticsBinder binder = new ConnectivityDiagnosticsBinder(callback, e);
727 if (sCallbacks.putIfAbsent(callback, binder) != null) {
728 throw new IllegalArgumentException("Callback is currently registered");
729 }
730
731 try {
Cody Kestingd198ed02020-01-05 14:06:39 -0800732 mService.registerConnectivityDiagnosticsCallback(
733 binder, request, mContext.getOpPackageName());
Cody Kesting63e4e002019-12-18 10:57:50 -0800734 } catch (RemoteException exception) {
735 exception.rethrowFromSystemServer();
736 }
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800737 }
738
739 /**
740 * Unregisters a ConnectivityDiagnosticsCallback with the System.
741 *
742 * <p>If the given callback is not currently registered with the System, this operation will be
743 * a no-op.
744 *
745 * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System.
746 */
747 public void unregisterConnectivityDiagnosticsCallback(
748 @NonNull ConnectivityDiagnosticsCallback callback) {
Cody Kesting63e4e002019-12-18 10:57:50 -0800749 // unconditionally removing from sCallbacks prevents race conditions here, since remove() is
750 // atomic.
751 final ConnectivityDiagnosticsBinder binder = sCallbacks.remove(callback);
752 if (binder == null) return;
753
754 try {
755 mService.unregisterConnectivityDiagnosticsCallback(binder);
756 } catch (RemoteException exception) {
757 exception.rethrowFromSystemServer();
758 }
Cody Kesting9a80eaf2019-12-11 08:34:51 -0800759 }
760}