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 32 import java.lang.annotation.Retention; 33 import java.lang.annotation.RetentionPolicy; 34 import java.util.Map; 35 import java.util.Objects; 36 import java.util.concurrent.ConcurrentHashMap; 37 import java.util.concurrent.Executor; 38 39 /** 40 * Class that provides utilities for collecting network connectivity diagnostics information. 41 * Connectivity information is made available through triggerable diagnostics tools and by listening 42 * to System validations. Some diagnostics information may be permissions-restricted. 43 * 44 * <p>ConnectivityDiagnosticsManager is intended for use by applications offering network 45 * connectivity on a user device. These tools will provide several mechanisms for these applications 46 * to be alerted to network conditions as well as diagnose potential network issues themselves. 47 * 48 * <p>The primary responsibilities of this class are to: 49 * 50 * <ul> 51 * <li>Allow permissioned applications to register and unregister callbacks for network event 52 * notifications 53 * <li>Invoke callbacks for network event notifications, including: 54 * <ul> 55 * <li>Network validations 56 * <li>Data stalls 57 * <li>Connectivity reports from applications 58 * </ul> 59 * </ul> 60 */ 61 public class ConnectivityDiagnosticsManager { 62 /** @hide */ 63 @VisibleForTesting 64 public static final Map<ConnectivityDiagnosticsCallback, ConnectivityDiagnosticsBinder> 65 sCallbacks = new ConcurrentHashMap<>(); 66 67 private final Context mContext; 68 private final IConnectivityManager mService; 69 70 /** @hide */ ConnectivityDiagnosticsManager(Context context, IConnectivityManager service)71 public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) { 72 mContext = Objects.requireNonNull(context, "missing context"); 73 mService = Objects.requireNonNull(service, "missing IConnectivityManager"); 74 } 75 76 /** @hide */ 77 @VisibleForTesting persistableBundleEquals( @ullable PersistableBundle a, @Nullable PersistableBundle b)78 public static boolean persistableBundleEquals( 79 @Nullable PersistableBundle a, @Nullable PersistableBundle b) { 80 if (a == b) return true; 81 if (a == null || b == null) return false; 82 if (!Objects.equals(a.keySet(), b.keySet())) return false; 83 for (String key : a.keySet()) { 84 if (!Objects.equals(a.get(key), b.get(key))) return false; 85 } 86 return true; 87 } 88 89 /** Class that includes connectivity information for a specific Network at a specific time. */ 90 public static final class ConnectivityReport implements Parcelable { 91 /** 92 * The overall status of the network is that it is invalid; it neither provides 93 * connectivity nor has been exempted from validation. 94 */ 95 public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; 96 97 /** 98 * The overall status of the network is that it is valid, this may be because it provides 99 * full Internet access (all probes succeeded), or because other properties of the network 100 * caused probes not to be run. 101 */ 102 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID 103 public static final int NETWORK_VALIDATION_RESULT_VALID = 1; 104 105 /** 106 * The overall status of the network is that it provides partial connectivity; some 107 * probed services succeeded but others failed. 108 */ 109 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL; 110 public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; 111 112 /** 113 * Due to the properties of the network, validation was not performed. 114 */ 115 public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; 116 117 /** @hide */ 118 @IntDef( 119 prefix = {"NETWORK_VALIDATION_RESULT_"}, 120 value = { 121 NETWORK_VALIDATION_RESULT_INVALID, 122 NETWORK_VALIDATION_RESULT_VALID, 123 NETWORK_VALIDATION_RESULT_PARTIALLY_VALID, 124 NETWORK_VALIDATION_RESULT_SKIPPED 125 }) 126 @Retention(RetentionPolicy.SOURCE) 127 public @interface NetworkValidationResult {} 128 129 /** 130 * The overall validation result for the Network being reported on. 131 * 132 * <p>The possible values for this key are: 133 * {@link #NETWORK_VALIDATION_RESULT_INVALID}, 134 * {@link #NETWORK_VALIDATION_RESULT_VALID}, 135 * {@link #NETWORK_VALIDATION_RESULT_PARTIALLY_VALID}, 136 * {@link #NETWORK_VALIDATION_RESULT_SKIPPED}. 137 * 138 * @see android.net.NetworkCapabilities#NET_CAPABILITY_VALIDATED 139 */ 140 @NetworkValidationResult 141 public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult"; 142 143 /** DNS probe. */ 144 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS 145 public static final int NETWORK_PROBE_DNS = 0x04; 146 147 /** HTTP probe. */ 148 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP 149 public static final int NETWORK_PROBE_HTTP = 0x08; 150 151 /** HTTPS probe. */ 152 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS; 153 public static final int NETWORK_PROBE_HTTPS = 0x10; 154 155 /** Captive portal fallback probe. */ 156 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_FALLBACK 157 public static final int NETWORK_PROBE_FALLBACK = 0x20; 158 159 /** Private DNS (DNS over TLS) probd. */ 160 // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS 161 public static final int NETWORK_PROBE_PRIVATE_DNS = 0x40; 162 163 /** @hide */ 164 @IntDef( 165 prefix = {"NETWORK_PROBE_"}, 166 value = { 167 NETWORK_PROBE_DNS, 168 NETWORK_PROBE_HTTP, 169 NETWORK_PROBE_HTTPS, 170 NETWORK_PROBE_FALLBACK, 171 NETWORK_PROBE_PRIVATE_DNS 172 }) 173 @Retention(RetentionPolicy.SOURCE) 174 public @interface NetworkProbe {} 175 176 /** 177 * A bitmask of network validation probes that succeeded. 178 * 179 * <p>The possible bits values reported by this key are: 180 * {@link #NETWORK_PROBE_DNS}, 181 * {@link #NETWORK_PROBE_HTTP}, 182 * {@link #NETWORK_PROBE_HTTPS}, 183 * {@link #NETWORK_PROBE_FALLBACK}, 184 * {@link #NETWORK_PROBE_PRIVATE_DNS}. 185 */ 186 @NetworkProbe 187 public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = 188 "networkProbesSucceeded"; 189 190 /** 191 * A bitmask of network validation probes that were attempted. 192 * 193 * <p>These probes may have failed or may be incomplete at the time of this report. 194 * 195 * <p>The possible bits values reported by this key are: 196 * {@link #NETWORK_PROBE_DNS}, 197 * {@link #NETWORK_PROBE_HTTP}, 198 * {@link #NETWORK_PROBE_HTTPS}, 199 * {@link #NETWORK_PROBE_FALLBACK}, 200 * {@link #NETWORK_PROBE_PRIVATE_DNS}. 201 */ 202 @NetworkProbe 203 public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = 204 "networkProbesAttempted"; 205 206 /** @hide */ 207 @StringDef(prefix = {"KEY_"}, value = { 208 KEY_NETWORK_VALIDATION_RESULT, KEY_NETWORK_PROBES_SUCCEEDED_BITMASK, 209 KEY_NETWORK_PROBES_ATTEMPTED_BITMASK}) 210 @Retention(RetentionPolicy.SOURCE) 211 public @interface ConnectivityReportBundleKeys {} 212 213 /** The Network for which this ConnectivityReport applied */ 214 @NonNull private final Network mNetwork; 215 216 /** 217 * The timestamp for the report. The timestamp is taken from {@link 218 * System#currentTimeMillis}. 219 */ 220 private final long mReportTimestamp; 221 222 /** LinkProperties available on the Network at the reported timestamp */ 223 @NonNull private final LinkProperties mLinkProperties; 224 225 /** NetworkCapabilities available on the Network at the reported timestamp */ 226 @NonNull private final NetworkCapabilities mNetworkCapabilities; 227 228 /** PersistableBundle that may contain additional info about the report */ 229 @NonNull private final PersistableBundle mAdditionalInfo; 230 231 /** 232 * Constructor for ConnectivityReport. 233 * 234 * <p>Apps should obtain instances through {@link 235 * ConnectivityDiagnosticsCallback#onConnectivityReportAvailable} instead of instantiating 236 * their own instances (unless for testing purposes). 237 * 238 * @param network The Network for which this ConnectivityReport applies 239 * @param reportTimestamp The timestamp for the report 240 * @param linkProperties The LinkProperties available on network at reportTimestamp 241 * @param networkCapabilities The NetworkCapabilities available on network at 242 * reportTimestamp 243 * @param additionalInfo A PersistableBundle that may contain additional info about the 244 * report 245 */ ConnectivityReport( @onNull Network network, long reportTimestamp, @NonNull LinkProperties linkProperties, @NonNull NetworkCapabilities networkCapabilities, @NonNull PersistableBundle additionalInfo)246 public ConnectivityReport( 247 @NonNull Network network, 248 long reportTimestamp, 249 @NonNull LinkProperties linkProperties, 250 @NonNull NetworkCapabilities networkCapabilities, 251 @NonNull PersistableBundle additionalInfo) { 252 mNetwork = network; 253 mReportTimestamp = reportTimestamp; 254 mLinkProperties = new LinkProperties(linkProperties); 255 mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); 256 mAdditionalInfo = additionalInfo; 257 } 258 259 /** 260 * Returns the Network for this ConnectivityReport. 261 * 262 * @return The Network for which this ConnectivityReport applied 263 */ 264 @NonNull getNetwork()265 public Network getNetwork() { 266 return mNetwork; 267 } 268 269 /** 270 * Returns the epoch timestamp (milliseconds) for when this report was taken. 271 * 272 * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}. 273 */ getReportTimestamp()274 public long getReportTimestamp() { 275 return mReportTimestamp; 276 } 277 278 /** 279 * Returns the LinkProperties available when this report was taken. 280 * 281 * @return LinkProperties available on the Network at the reported timestamp 282 */ 283 @NonNull getLinkProperties()284 public LinkProperties getLinkProperties() { 285 return new LinkProperties(mLinkProperties); 286 } 287 288 /** 289 * Returns the NetworkCapabilities when this report was taken. 290 * 291 * @return NetworkCapabilities available on the Network at the reported timestamp 292 */ 293 @NonNull getNetworkCapabilities()294 public NetworkCapabilities getNetworkCapabilities() { 295 return new NetworkCapabilities(mNetworkCapabilities); 296 } 297 298 /** 299 * Returns a PersistableBundle with additional info for this report. 300 * 301 * @return PersistableBundle that may contain additional info about the report 302 */ 303 @NonNull getAdditionalInfo()304 public PersistableBundle getAdditionalInfo() { 305 return new PersistableBundle(mAdditionalInfo); 306 } 307 308 @Override equals(@ullable Object o)309 public boolean equals(@Nullable Object o) { 310 if (this == o) return true; 311 if (!(o instanceof ConnectivityReport)) return false; 312 final ConnectivityReport that = (ConnectivityReport) o; 313 314 // PersistableBundle is optimized to avoid unparcelling data unless fields are 315 // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over 316 // {@link PersistableBundle#kindofEquals}. 317 return mReportTimestamp == that.mReportTimestamp 318 && mNetwork.equals(that.mNetwork) 319 && mLinkProperties.equals(that.mLinkProperties) 320 && mNetworkCapabilities.equals(that.mNetworkCapabilities) 321 && persistableBundleEquals(mAdditionalInfo, that.mAdditionalInfo); 322 } 323 324 @Override hashCode()325 public int hashCode() { 326 return Objects.hash( 327 mNetwork, 328 mReportTimestamp, 329 mLinkProperties, 330 mNetworkCapabilities, 331 mAdditionalInfo); 332 } 333 334 /** {@inheritDoc} */ 335 @Override describeContents()336 public int describeContents() { 337 return 0; 338 } 339 340 /** {@inheritDoc} */ 341 @Override writeToParcel(@onNull Parcel dest, int flags)342 public void writeToParcel(@NonNull Parcel dest, int flags) { 343 dest.writeParcelable(mNetwork, flags); 344 dest.writeLong(mReportTimestamp); 345 dest.writeParcelable(mLinkProperties, flags); 346 dest.writeParcelable(mNetworkCapabilities, flags); 347 dest.writeParcelable(mAdditionalInfo, flags); 348 } 349 350 /** Implement the Parcelable interface */ 351 public static final @NonNull Creator<ConnectivityReport> CREATOR = 352 new Creator<ConnectivityReport>() { 353 public ConnectivityReport createFromParcel(Parcel in) { 354 return new ConnectivityReport( 355 in.readParcelable(null), 356 in.readLong(), 357 in.readParcelable(null), 358 in.readParcelable(null), 359 in.readParcelable(null)); 360 } 361 362 public ConnectivityReport[] newArray(int size) { 363 return new ConnectivityReport[size]; 364 } 365 }; 366 } 367 368 /** Class that includes information for a suspected data stall on a specific Network */ 369 public static final class DataStallReport implements Parcelable { 370 /** 371 * Indicates that the Data Stall was detected using DNS events. 372 */ 373 public static final int DETECTION_METHOD_DNS_EVENTS = 1; 374 375 /** 376 * Indicates that the Data Stall was detected using TCP metrics. 377 */ 378 public static final int DETECTION_METHOD_TCP_METRICS = 2; 379 380 /** @hide */ 381 @Retention(RetentionPolicy.SOURCE) 382 @IntDef( 383 prefix = {"DETECTION_METHOD_"}, 384 value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS}) 385 public @interface DetectionMethod {} 386 387 /** 388 * This key represents the period in milliseconds over which other included TCP metrics 389 * were measured. 390 * 391 * <p>This key will be included if the data stall detection method is 392 * {@link #DETECTION_METHOD_TCP_METRICS}. 393 * 394 * <p>This value is an int. 395 */ 396 public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = 397 "tcpMetricsCollectionPeriodMillis"; 398 399 /** 400 * This key represents the fail rate of TCP packets when the suspected data stall was 401 * detected. 402 * 403 * <p>This key will be included if the data stall detection method is 404 * {@link #DETECTION_METHOD_TCP_METRICS}. 405 * 406 * <p>This value is an int percentage between 0 and 100. 407 */ 408 public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate"; 409 410 /** 411 * This key represents the consecutive number of DNS timeouts that have occurred. 412 * 413 * <p>The consecutive count will be reset any time a DNS response is received. 414 * 415 * <p>This key will be included if the data stall detection method is 416 * {@link #DETECTION_METHOD_DNS_EVENTS}. 417 * 418 * <p>This value is an int. 419 */ 420 public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts"; 421 422 /** @hide */ 423 @Retention(RetentionPolicy.SOURCE) 424 @StringDef(prefix = {"KEY_"}, value = { 425 KEY_TCP_PACKET_FAIL_RATE, 426 KEY_DNS_CONSECUTIVE_TIMEOUTS 427 }) 428 public @interface DataStallReportBundleKeys {} 429 430 /** The Network for which this DataStallReport applied */ 431 @NonNull private final Network mNetwork; 432 433 /** 434 * The timestamp for the report. The timestamp is taken from {@link 435 * System#currentTimeMillis}. 436 */ 437 private long mReportTimestamp; 438 439 /** A bitmask of the detection methods used to identify the suspected data stall */ 440 @DetectionMethod private final int mDetectionMethod; 441 442 /** LinkProperties available on the Network at the reported timestamp */ 443 @NonNull private final LinkProperties mLinkProperties; 444 445 /** NetworkCapabilities available on the Network at the reported timestamp */ 446 @NonNull private final NetworkCapabilities mNetworkCapabilities; 447 448 /** PersistableBundle that may contain additional information on the suspected data stall */ 449 @NonNull private final PersistableBundle mStallDetails; 450 451 /** 452 * Constructor for DataStallReport. 453 * 454 * <p>Apps should obtain instances through {@link 455 * ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own 456 * instances (unless for testing purposes). 457 * 458 * @param network The Network for which this DataStallReport applies 459 * @param reportTimestamp The timestamp for the report 460 * @param detectionMethod The detection method used to identify this data stall 461 * @param linkProperties The LinkProperties available on network at reportTimestamp 462 * @param networkCapabilities The NetworkCapabilities available on network at 463 * reportTimestamp 464 * @param stallDetails A PersistableBundle that may contain additional info about the report 465 */ DataStallReport( @onNull Network network, long reportTimestamp, @DetectionMethod int detectionMethod, @NonNull LinkProperties linkProperties, @NonNull NetworkCapabilities networkCapabilities, @NonNull PersistableBundle stallDetails)466 public DataStallReport( 467 @NonNull Network network, 468 long reportTimestamp, 469 @DetectionMethod int detectionMethod, 470 @NonNull LinkProperties linkProperties, 471 @NonNull NetworkCapabilities networkCapabilities, 472 @NonNull PersistableBundle stallDetails) { 473 mNetwork = network; 474 mReportTimestamp = reportTimestamp; 475 mDetectionMethod = detectionMethod; 476 mLinkProperties = new LinkProperties(linkProperties); 477 mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); 478 mStallDetails = stallDetails; 479 } 480 481 /** 482 * Returns the Network for this DataStallReport. 483 * 484 * @return The Network for which this DataStallReport applied 485 */ 486 @NonNull getNetwork()487 public Network getNetwork() { 488 return mNetwork; 489 } 490 491 /** 492 * Returns the epoch timestamp (milliseconds) for when this report was taken. 493 * 494 * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}. 495 */ getReportTimestamp()496 public long getReportTimestamp() { 497 return mReportTimestamp; 498 } 499 500 /** 501 * Returns the bitmask of detection methods used to identify this suspected data stall. 502 * 503 * @return The bitmask of detection methods used to identify the suspected data stall 504 */ getDetectionMethod()505 public int getDetectionMethod() { 506 return mDetectionMethod; 507 } 508 509 /** 510 * Returns the LinkProperties available when this report was taken. 511 * 512 * @return LinkProperties available on the Network at the reported timestamp 513 */ 514 @NonNull getLinkProperties()515 public LinkProperties getLinkProperties() { 516 return new LinkProperties(mLinkProperties); 517 } 518 519 /** 520 * Returns the NetworkCapabilities when this report was taken. 521 * 522 * @return NetworkCapabilities available on the Network at the reported timestamp 523 */ 524 @NonNull getNetworkCapabilities()525 public NetworkCapabilities getNetworkCapabilities() { 526 return new NetworkCapabilities(mNetworkCapabilities); 527 } 528 529 /** 530 * Returns a PersistableBundle with additional info for this report. 531 * 532 * <p>Gets a bundle with details about the suspected data stall including information 533 * specific to the monitoring method that detected the data stall. 534 * 535 * @return PersistableBundle that may contain additional information on the suspected data 536 * stall 537 */ 538 @NonNull getStallDetails()539 public PersistableBundle getStallDetails() { 540 return new PersistableBundle(mStallDetails); 541 } 542 543 @Override equals(@ullable Object o)544 public boolean equals(@Nullable Object o) { 545 if (this == o) return true; 546 if (!(o instanceof DataStallReport)) return false; 547 final DataStallReport that = (DataStallReport) o; 548 549 // PersistableBundle is optimized to avoid unparcelling data unless fields are 550 // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over 551 // {@link PersistableBundle#kindofEquals}. 552 return mReportTimestamp == that.mReportTimestamp 553 && mDetectionMethod == that.mDetectionMethod 554 && mNetwork.equals(that.mNetwork) 555 && mLinkProperties.equals(that.mLinkProperties) 556 && mNetworkCapabilities.equals(that.mNetworkCapabilities) 557 && persistableBundleEquals(mStallDetails, that.mStallDetails); 558 } 559 560 @Override hashCode()561 public int hashCode() { 562 return Objects.hash( 563 mNetwork, 564 mReportTimestamp, 565 mDetectionMethod, 566 mLinkProperties, 567 mNetworkCapabilities, 568 mStallDetails); 569 } 570 571 /** {@inheritDoc} */ 572 @Override describeContents()573 public int describeContents() { 574 return 0; 575 } 576 577 /** {@inheritDoc} */ 578 @Override writeToParcel(@onNull Parcel dest, int flags)579 public void writeToParcel(@NonNull Parcel dest, int flags) { 580 dest.writeParcelable(mNetwork, flags); 581 dest.writeLong(mReportTimestamp); 582 dest.writeInt(mDetectionMethod); 583 dest.writeParcelable(mLinkProperties, flags); 584 dest.writeParcelable(mNetworkCapabilities, flags); 585 dest.writeParcelable(mStallDetails, flags); 586 } 587 588 /** Implement the Parcelable interface */ 589 public static final @NonNull Creator<DataStallReport> CREATOR = 590 new Creator<DataStallReport>() { 591 public DataStallReport createFromParcel(Parcel in) { 592 return new DataStallReport( 593 in.readParcelable(null), 594 in.readLong(), 595 in.readInt(), 596 in.readParcelable(null), 597 in.readParcelable(null), 598 in.readParcelable(null)); 599 } 600 601 public DataStallReport[] newArray(int size) { 602 return new DataStallReport[size]; 603 } 604 }; 605 } 606 607 /** @hide */ 608 @VisibleForTesting 609 public static class ConnectivityDiagnosticsBinder 610 extends IConnectivityDiagnosticsCallback.Stub { 611 @NonNull private final ConnectivityDiagnosticsCallback mCb; 612 @NonNull private final Executor mExecutor; 613 614 /** @hide */ 615 @VisibleForTesting ConnectivityDiagnosticsBinder( @onNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor)616 public ConnectivityDiagnosticsBinder( 617 @NonNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor) { 618 this.mCb = cb; 619 this.mExecutor = executor; 620 } 621 622 /** @hide */ 623 @VisibleForTesting onConnectivityReportAvailable(@onNull ConnectivityReport report)624 public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) { 625 final long token = Binder.clearCallingIdentity(); 626 try { 627 mExecutor.execute(() -> { 628 mCb.onConnectivityReportAvailable(report); 629 }); 630 } finally { 631 Binder.restoreCallingIdentity(token); 632 } 633 } 634 635 /** @hide */ 636 @VisibleForTesting onDataStallSuspected(@onNull DataStallReport report)637 public void onDataStallSuspected(@NonNull DataStallReport report) { 638 final long token = Binder.clearCallingIdentity(); 639 try { 640 mExecutor.execute(() -> { 641 mCb.onDataStallSuspected(report); 642 }); 643 } finally { 644 Binder.restoreCallingIdentity(token); 645 } 646 } 647 648 /** @hide */ 649 @VisibleForTesting onNetworkConnectivityReported( @onNull Network network, boolean hasConnectivity)650 public void onNetworkConnectivityReported( 651 @NonNull Network network, boolean hasConnectivity) { 652 final long token = Binder.clearCallingIdentity(); 653 try { 654 mExecutor.execute(() -> { 655 mCb.onNetworkConnectivityReported(network, hasConnectivity); 656 }); 657 } finally { 658 Binder.restoreCallingIdentity(token); 659 } 660 } 661 } 662 663 /** 664 * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about 665 * network connectivity events. Must be extended by applications wanting notifications. 666 */ 667 public abstract static class ConnectivityDiagnosticsCallback { 668 /** 669 * Called when the platform completes a data connectivity check. This will also be invoked 670 * immediately upon registration for each network matching the request with the latest 671 * report, if a report has already been generated for that network. 672 * 673 * <p>The Network specified in the ConnectivityReport may not be active any more when this 674 * method is invoked. 675 * 676 * @param report The ConnectivityReport containing information about a connectivity check 677 */ onConnectivityReportAvailable(@onNull ConnectivityReport report)678 public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {} 679 680 /** 681 * Called when the platform suspects a data stall on some Network. 682 * 683 * <p>The Network specified in the DataStallReport may not be active any more when this 684 * method is invoked. 685 * 686 * @param report The DataStallReport containing information about the suspected data stall 687 */ onDataStallSuspected(@onNull DataStallReport report)688 public void onDataStallSuspected(@NonNull DataStallReport report) {} 689 690 /** 691 * Called when any app reports connectivity to the System. 692 * 693 * @param network The Network for which connectivity has been reported 694 * @param hasConnectivity The connectivity reported to the System 695 */ onNetworkConnectivityReported( @onNull Network network, boolean hasConnectivity)696 public void onNetworkConnectivityReported( 697 @NonNull Network network, boolean hasConnectivity) {} 698 } 699 700 /** 701 * Registers a ConnectivityDiagnosticsCallback with the System. 702 * 703 * <p>Only apps that offer network connectivity to the user should be registering callbacks. 704 * These are the only apps whose callbacks will be invoked by the system. Apps considered to 705 * meet these conditions include: 706 * 707 * <ul> 708 * <li>Carrier apps with active subscriptions 709 * <li>Active VPNs 710 * <li>WiFi Suggesters 711 * </ul> 712 * 713 * <p>Callbacks registered by apps not meeting the above criteria will not be invoked. 714 * 715 * <p>If a registering app loses its relevant permissions, any callbacks it registered will 716 * silently stop receiving callbacks. Note that registering apps must also have location 717 * permissions to receive callbacks as some Networks may be location-bound (such as WiFi 718 * networks). 719 * 720 * <p>Each register() call <b>MUST</b> use a ConnectivityDiagnosticsCallback instance that is 721 * not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with 722 * multiple NetworkRequests, an IllegalArgumentException will be thrown. 723 * 724 * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the 725 * number of outstanding requests to 100 per app (identified by their UID), shared with 726 * callbacks in {@link ConnectivityManager}. Registering a callback with this method will count 727 * toward this limit. If this limit is exceeded, an exception will be thrown. To avoid hitting 728 * this issue and to conserve resources, make sure to unregister the callbacks with 729 * {@link #unregisterConnectivityDiagnosticsCallback}. 730 * 731 * @param request The NetworkRequest that will be used to match with Networks for which 732 * callbacks will be fired 733 * @param e The Executor to be used for running the callback method invocations 734 * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the 735 * System 736 * @throws IllegalArgumentException if the same callback instance is registered with multiple 737 * NetworkRequests 738 * @throws RuntimeException if the app already has too many callbacks registered. 739 */ registerConnectivityDiagnosticsCallback( @onNull NetworkRequest request, @NonNull Executor e, @NonNull ConnectivityDiagnosticsCallback callback)740 public void registerConnectivityDiagnosticsCallback( 741 @NonNull NetworkRequest request, 742 @NonNull Executor e, 743 @NonNull ConnectivityDiagnosticsCallback callback) { 744 final ConnectivityDiagnosticsBinder binder = new ConnectivityDiagnosticsBinder(callback, e); 745 if (sCallbacks.putIfAbsent(callback, binder) != null) { 746 throw new IllegalArgumentException("Callback is currently registered"); 747 } 748 749 try { 750 mService.registerConnectivityDiagnosticsCallback( 751 binder, request, mContext.getOpPackageName()); 752 } catch (RemoteException exception) { 753 exception.rethrowFromSystemServer(); 754 } 755 } 756 757 /** 758 * Unregisters a ConnectivityDiagnosticsCallback with the System. 759 * 760 * <p>If the given callback is not currently registered with the System, this operation will be 761 * a no-op. 762 * 763 * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System. 764 */ unregisterConnectivityDiagnosticsCallback( @onNull ConnectivityDiagnosticsCallback callback)765 public void unregisterConnectivityDiagnosticsCallback( 766 @NonNull ConnectivityDiagnosticsCallback callback) { 767 // unconditionally removing from sCallbacks prevents race conditions here, since remove() is 768 // atomic. 769 final ConnectivityDiagnosticsBinder binder = sCallbacks.remove(callback); 770 if (binder == null) return; 771 772 try { 773 mService.unregisterConnectivityDiagnosticsCallback(binder); 774 } catch (RemoteException exception) { 775 exception.rethrowFromSystemServer(); 776 } 777 } 778 } 779