1 /* 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 17 package android.net; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.StringDef; 23 import android.content.Context; 24 import android.os.Binder; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.os.PersistableBundle; 28 import android.os.RemoteException; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 import com.android.internal.util.Preconditions; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.util.Map; 36 import java.util.Objects; 37 import java.util.concurrent.ConcurrentHashMap; 38 import 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 */ 62 public class ConnectivityDiagnosticsManager { 63 /** @hide */ 64 @VisibleForTesting 65 public static final Map<ConnectivityDiagnosticsCallback, ConnectivityDiagnosticsBinder> 66 sCallbacks = new ConcurrentHashMap<>(); 67 68 private final Context mContext; 69 private final IConnectivityManager mService; 70 71 /** @hide */ ConnectivityDiagnosticsManager(Context context, IConnectivityManager service)72 public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) { 73 mContext = Preconditions.checkNotNull(context, "missing context"); 74 mService = Preconditions.checkNotNull(service, "missing IConnectivityManager"); 75 } 76 77 /** @hide */ 78 @VisibleForTesting persistableBundleEquals( @ullable PersistableBundle a, @Nullable PersistableBundle b)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 90 /** Class that includes connectivity information for a specific Network at a specific time. */ 91 public static final class ConnectivityReport implements Parcelable { 92 /** 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 * 139 * @see android.net.NetworkCapabilities#NET_CAPABILITY_VALIDATED 140 */ 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 = 205 "networkProbesAttempted"; 206 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 214 /** The Network for which this ConnectivityReport applied */ 215 @NonNull private final Network mNetwork; 216 217 /** 218 * The timestamp for the report. The timestamp is taken from {@link 219 * System#currentTimeMillis}. 220 */ 221 private final long mReportTimestamp; 222 223 /** LinkProperties available on the Network at the reported timestamp */ 224 @NonNull private final LinkProperties mLinkProperties; 225 226 /** NetworkCapabilities available on the Network at the reported timestamp */ 227 @NonNull private final NetworkCapabilities mNetworkCapabilities; 228 229 /** PersistableBundle that may contain additional info about the report */ 230 @NonNull private final PersistableBundle mAdditionalInfo; 231 232 /** 233 * Constructor for ConnectivityReport. 234 * 235 * <p>Apps should obtain instances through {@link 236 * ConnectivityDiagnosticsCallback#onConnectivityReportAvailable} instead of instantiating 237 * their own instances (unless for testing purposes). 238 * 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 */ ConnectivityReport( @onNull Network network, long reportTimestamp, @NonNull LinkProperties linkProperties, @NonNull NetworkCapabilities networkCapabilities, @NonNull PersistableBundle additionalInfo)247 public ConnectivityReport( 248 @NonNull Network network, 249 long reportTimestamp, 250 @NonNull LinkProperties linkProperties, 251 @NonNull NetworkCapabilities networkCapabilities, 252 @NonNull PersistableBundle additionalInfo) { 253 mNetwork = network; 254 mReportTimestamp = reportTimestamp; 255 mLinkProperties = new LinkProperties(linkProperties); 256 mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); 257 mAdditionalInfo = additionalInfo; 258 } 259 260 /** 261 * Returns the Network for this ConnectivityReport. 262 * 263 * @return The Network for which this ConnectivityReport applied 264 */ 265 @NonNull getNetwork()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 */ getReportTimestamp()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 getLinkProperties()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 getNetworkCapabilities()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 getAdditionalInfo()305 public PersistableBundle getAdditionalInfo() { 306 return new PersistableBundle(mAdditionalInfo); 307 } 308 309 @Override equals(@ullable Object o)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 hashCode()326 public int hashCode() { 327 return Objects.hash( 328 mNetwork, 329 mReportTimestamp, 330 mLinkProperties, 331 mNetworkCapabilities, 332 mAdditionalInfo); 333 } 334 335 /** {@inheritDoc} */ 336 @Override describeContents()337 public int describeContents() { 338 return 0; 339 } 340 341 /** {@inheritDoc} */ 342 @Override writeToParcel(@onNull Parcel dest, int flags)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 = 353 new Creator<ConnectivityReport>() { 354 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 }; 367 } 368 369 /** Class that includes information for a suspected data stall on a specific Network */ 370 public static final class DataStallReport implements Parcelable { 371 /** 372 * Indicates that the Data Stall was detected using DNS events. 373 */ 374 public static final int DETECTION_METHOD_DNS_EVENTS = 1; 375 376 /** 377 * Indicates that the Data Stall was detected using TCP metrics. 378 */ 379 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 388 /** 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 431 /** The Network for which this DataStallReport applied */ 432 @NonNull private final Network mNetwork; 433 434 /** 435 * The timestamp for the report. The timestamp is taken from {@link 436 * System#currentTimeMillis}. 437 */ 438 private long mReportTimestamp; 439 440 /** A bitmask of the detection methods used to identify the suspected data stall */ 441 @DetectionMethod private final int mDetectionMethod; 442 443 /** 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 449 /** PersistableBundle that may contain additional information on the suspected data stall */ 450 @NonNull private final PersistableBundle mStallDetails; 451 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 462 * @param linkProperties The LinkProperties available on network at reportTimestamp 463 * @param networkCapabilities The NetworkCapabilities available on network at 464 * reportTimestamp 465 * @param stallDetails A PersistableBundle that may contain additional info about the report 466 */ DataStallReport( @onNull Network network, long reportTimestamp, @DetectionMethod int detectionMethod, @NonNull LinkProperties linkProperties, @NonNull NetworkCapabilities networkCapabilities, @NonNull PersistableBundle stallDetails)467 public DataStallReport( 468 @NonNull Network network, 469 long reportTimestamp, 470 @DetectionMethod int detectionMethod, 471 @NonNull LinkProperties linkProperties, 472 @NonNull NetworkCapabilities networkCapabilities, 473 @NonNull PersistableBundle stallDetails) { 474 mNetwork = network; 475 mReportTimestamp = reportTimestamp; 476 mDetectionMethod = detectionMethod; 477 mLinkProperties = new LinkProperties(linkProperties); 478 mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); 479 mStallDetails = stallDetails; 480 } 481 482 /** 483 * Returns the Network for this DataStallReport. 484 * 485 * @return The Network for which this DataStallReport applied 486 */ 487 @NonNull getNetwork()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 */ getReportTimestamp()497 public long getReportTimestamp() { 498 return mReportTimestamp; 499 } 500 501 /** 502 * Returns the bitmask of detection methods used to identify this suspected data stall. 503 * 504 * @return The bitmask of detection methods used to identify the suspected data stall 505 */ getDetectionMethod()506 public int getDetectionMethod() { 507 return mDetectionMethod; 508 } 509 510 /** 511 * Returns the LinkProperties available when this report was taken. 512 * 513 * @return LinkProperties available on the Network at the reported timestamp 514 */ 515 @NonNull getLinkProperties()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 getNetworkCapabilities()526 public NetworkCapabilities getNetworkCapabilities() { 527 return new NetworkCapabilities(mNetworkCapabilities); 528 } 529 530 /** 531 * Returns a PersistableBundle with additional info for this report. 532 * 533 * <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 * 536 * @return PersistableBundle that may contain additional information on the suspected data 537 * stall 538 */ 539 @NonNull getStallDetails()540 public PersistableBundle getStallDetails() { 541 return new PersistableBundle(mStallDetails); 542 } 543 544 @Override equals(@ullable Object o)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) 556 && mLinkProperties.equals(that.mLinkProperties) 557 && mNetworkCapabilities.equals(that.mNetworkCapabilities) 558 && persistableBundleEquals(mStallDetails, that.mStallDetails); 559 } 560 561 @Override hashCode()562 public int hashCode() { 563 return Objects.hash( 564 mNetwork, 565 mReportTimestamp, 566 mDetectionMethod, 567 mLinkProperties, 568 mNetworkCapabilities, 569 mStallDetails); 570 } 571 572 /** {@inheritDoc} */ 573 @Override describeContents()574 public int describeContents() { 575 return 0; 576 } 577 578 /** {@inheritDoc} */ 579 @Override writeToParcel(@onNull Parcel dest, int flags)580 public void writeToParcel(@NonNull Parcel dest, int flags) { 581 dest.writeParcelable(mNetwork, flags); 582 dest.writeLong(mReportTimestamp); 583 dest.writeInt(mDetectionMethod); 584 dest.writeParcelable(mLinkProperties, flags); 585 dest.writeParcelable(mNetworkCapabilities, flags); 586 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(), 597 in.readParcelable(null), 598 in.readParcelable(null), 599 in.readParcelable(null)); 600 } 601 602 public DataStallReport[] newArray(int size) { 603 return new DataStallReport[size]; 604 } 605 }; 606 } 607 608 /** @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 ConnectivityDiagnosticsBinder( @onNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor)617 public ConnectivityDiagnosticsBinder( 618 @NonNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor) { 619 this.mCb = cb; 620 this.mExecutor = executor; 621 } 622 623 /** @hide */ 624 @VisibleForTesting onConnectivityReportAvailable(@onNull ConnectivityReport report)625 public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) { 626 Binder.withCleanCallingIdentity(() -> { 627 mExecutor.execute(() -> { 628 mCb.onConnectivityReportAvailable(report); 629 }); 630 }); 631 } 632 633 /** @hide */ 634 @VisibleForTesting onDataStallSuspected(@onNull DataStallReport report)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 onNetworkConnectivityReported( @onNull Network network, boolean hasConnectivity)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 655 /** 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 662 * immediately upon registration for each network matching the request with the latest 663 * report, if a report has already been generated for that network. 664 * 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 */ onConnectivityReportAvailable(@onNull ConnectivityReport report)670 public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {} 671 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 */ onDataStallSuspected(@onNull DataStallReport report)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 */ onNetworkConnectivityReported( @onNull Network network, boolean hasConnectivity)688 public void onNetworkConnectivityReported( 689 @NonNull Network network, boolean hasConnectivity) {} 690 } 691 692 /** 693 * Registers a ConnectivityDiagnosticsCallback with the System. 694 * 695 * <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: 698 * 699 * <ul> 700 * <li>Carrier apps with active subscriptions 701 * <li>Active VPNs 702 * <li>WiFi Suggesters 703 * </ul> 704 * 705 * <p>Callbacks registered by apps not meeting the above criteria will not be invoked. 706 * 707 * <p>If a registering app loses its relevant permissions, any callbacks it registered will 708 * silently stop receiving callbacks. 709 * 710 * <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. 713 * 714 * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the 715 * number of outstanding requests to 100 per app (identified by their UID), shared with 716 * callbacks in {@link ConnectivityManager}. Registering a callback with this method will count 717 * toward this limit. If this limit is exceeded, an exception will be thrown. To avoid hitting 718 * this issue and to conserve resources, make sure to unregister the callbacks with 719 * {@link #unregisterConnectivityDiagnosticsCallback}. 720 * 721 * @param request The NetworkRequest that will be used to match with Networks for which 722 * callbacks will be fired 723 * @param e The Executor to be used for running the callback method invocations 724 * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the 725 * System 726 * @throws IllegalArgumentException if the same callback instance is registered with multiple 727 * NetworkRequests 728 * @throws RuntimeException if the app already has too many callbacks registered. 729 */ registerConnectivityDiagnosticsCallback( @onNull NetworkRequest request, @NonNull Executor e, @NonNull ConnectivityDiagnosticsCallback callback)730 public void registerConnectivityDiagnosticsCallback( 731 @NonNull NetworkRequest request, 732 @NonNull Executor e, 733 @NonNull ConnectivityDiagnosticsCallback callback) { 734 final ConnectivityDiagnosticsBinder binder = new ConnectivityDiagnosticsBinder(callback, e); 735 if (sCallbacks.putIfAbsent(callback, binder) != null) { 736 throw new IllegalArgumentException("Callback is currently registered"); 737 } 738 739 try { 740 mService.registerConnectivityDiagnosticsCallback( 741 binder, request, mContext.getOpPackageName()); 742 } catch (RemoteException exception) { 743 exception.rethrowFromSystemServer(); 744 } 745 } 746 747 /** 748 * Unregisters a ConnectivityDiagnosticsCallback with the System. 749 * 750 * <p>If the given callback is not currently registered with the System, this operation will be 751 * a no-op. 752 * 753 * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System. 754 */ unregisterConnectivityDiagnosticsCallback( @onNull ConnectivityDiagnosticsCallback callback)755 public void unregisterConnectivityDiagnosticsCallback( 756 @NonNull ConnectivityDiagnosticsCallback callback) { 757 // unconditionally removing from sCallbacks prevents race conditions here, since remove() is 758 // atomic. 759 final ConnectivityDiagnosticsBinder binder = sCallbacks.remove(callback); 760 if (binder == null) return; 761 762 try { 763 mService.unregisterConnectivityDiagnosticsCallback(binder); 764 } catch (RemoteException exception) { 765 exception.rethrowFromSystemServer(); 766 } 767 } 768 } 769