1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
|
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.BitUtils;
import com.android.internal.util.Preconditions;
import java.util.Objects;
import java.util.StringJoiner;
/**
* This class represents the capabilities of a network. This is used both to specify
* needs to {@link ConnectivityManager} and when inspecting a network.
*
* Note that this replaces the old {@link ConnectivityManager#TYPE_MOBILE} method
* of network selection. Rather than indicate a need for Wi-Fi because an application
* needs high bandwidth and risk obsolescence when a new, fast network appears (like LTE),
* the application should specify it needs high bandwidth. Similarly if an application
* needs an unmetered network for a bulk transfer it can specify that rather than assuming
* all cellular based connections are metered and all Wi-Fi based connections are not.
*/
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
/**
* @hide
*/
public NetworkCapabilities() {
clearAll();
mNetworkCapabilities = DEFAULT_CAPABILITIES;
}
public NetworkCapabilities(NetworkCapabilities nc) {
if (nc != null) {
mNetworkCapabilities = nc.mNetworkCapabilities;
mTransportTypes = nc.mTransportTypes;
mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
mNetworkSpecifier = nc.mNetworkSpecifier;
mSignalStrength = nc.mSignalStrength;
}
}
/**
* Completely clears the contents of this object, removing even the capabilities that are set
* by default when the object is constructed.
* @hide
*/
public void clearAll() {
mNetworkCapabilities = mTransportTypes = 0;
mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = 0;
mNetworkSpecifier = null;
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
}
/**
* Represents the network's capabilities. If any are specified they will be satisfied
* by any Network that matches all of them.
*/
private long mNetworkCapabilities;
/**
* Indicates this is a network that has the ability to reach the
* carrier's MMSC for sending and receiving MMS messages.
*/
public static final int NET_CAPABILITY_MMS = 0;
/**
* Indicates this is a network that has the ability to reach the carrier's
* SUPL server, used to retrieve GPS information.
*/
public static final int NET_CAPABILITY_SUPL = 1;
/**
* Indicates this is a network that has the ability to reach the carrier's
* DUN or tethering gateway.
*/
public static final int NET_CAPABILITY_DUN = 2;
/**
* Indicates this is a network that has the ability to reach the carrier's
* FOTA portal, used for over the air updates.
*/
public static final int NET_CAPABILITY_FOTA = 3;
/**
* Indicates this is a network that has the ability to reach the carrier's
* IMS servers, used for network registration and signaling.
*/
public static final int NET_CAPABILITY_IMS = 4;
/**
* Indicates this is a network that has the ability to reach the carrier's
* CBS servers, used for carrier specific services.
*/
public static final int NET_CAPABILITY_CBS = 5;
/**
* Indicates this is a network that has the ability to reach a Wi-Fi direct
* peer.
*/
public static final int NET_CAPABILITY_WIFI_P2P = 6;
/**
* Indicates this is a network that has the ability to reach a carrier's
* Initial Attach servers.
*/
public static final int NET_CAPABILITY_IA = 7;
/**
* Indicates this is a network that has the ability to reach a carrier's
* RCS servers, used for Rich Communication Services.
*/
public static final int NET_CAPABILITY_RCS = 8;
/**
* Indicates this is a network that has the ability to reach a carrier's
* XCAP servers, used for configuration and control.
*/
public static final int NET_CAPABILITY_XCAP = 9;
/**
* Indicates this is a network that has the ability to reach a carrier's
* Emergency IMS servers or other services, used for network signaling
* during emergency calls.
*/
public static final int NET_CAPABILITY_EIMS = 10;
/**
* Indicates that this network is unmetered.
*/
public static final int NET_CAPABILITY_NOT_METERED = 11;
/**
* Indicates that this network should be able to reach the internet.
*/
public static final int NET_CAPABILITY_INTERNET = 12;
/**
* Indicates that this network is available for general use. If this is not set
* applications should not attempt to communicate on this network. Note that this
* is simply informative and not enforcement - enforcement is handled via other means.
* Set by default.
*/
public static final int NET_CAPABILITY_NOT_RESTRICTED = 13;
/**
* Indicates that the user has indicated implicit trust of this network. This
* generally means it's a sim-selected carrier, a plugged in ethernet, a paired
* BT device or a wifi the user asked to connect to. Untrusted networks
* are probably limited to unknown wifi AP. Set by default.
*/
public static final int NET_CAPABILITY_TRUSTED = 14;
/**
* Indicates that this network is not a VPN. This capability is set by default and should be
* explicitly cleared for VPN networks.
*/
public static final int NET_CAPABILITY_NOT_VPN = 15;
/**
* Indicates that connectivity on this network was successfully validated. For example, for a
* network with NET_CAPABILITY_INTERNET, it means that Internet connectivity was successfully
* detected.
*/
public static final int NET_CAPABILITY_VALIDATED = 16;
/**
* Indicates that this network was found to have a captive portal in place last time it was
* probed.
*/
public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;
/**
* Indicates that this network is available for use by apps, and not a network that is being
* kept up in the background to facilitate fast network switching.
* @hide
*/
public static final int NET_CAPABILITY_FOREGROUND = 18;
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_FOREGROUND;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
* network is connected.
*/
private static final long MUTABLE_CAPABILITIES =
// TRUSTED can change when user explicitly connects to an untrusted network in Settings.
// http://b/18206275
(1 << NET_CAPABILITY_TRUSTED) |
(1 << NET_CAPABILITY_VALIDATED) |
(1 << NET_CAPABILITY_CAPTIVE_PORTAL) |
(1 << NET_CAPABILITY_FOREGROUND);
/**
* Network capabilities that are not allowed in NetworkRequests. This exists because the
* NetworkFactory / NetworkAgent model does not deal well with the situation where a
* capability's presence cannot be known in advance. If such a capability is requested, then we
* can get into a cycle where the NetworkFactory endlessly churns out NetworkAgents that then
* get immediately torn down because they do not have the requested capability.
*/
private static final long NON_REQUESTABLE_CAPABILITIES =
MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_TRUSTED);
/**
* Capabilities that are set by default when the object is constructed.
*/
private static final long DEFAULT_CAPABILITIES =
(1 << NET_CAPABILITY_NOT_RESTRICTED) |
(1 << NET_CAPABILITY_TRUSTED) |
(1 << NET_CAPABILITY_NOT_VPN);
/**
* Capabilities that suggest that a network is restricted.
* {@see #maybeMarkCapabilitiesRestricted}.
*/
@VisibleForTesting
/* package */ static final long RESTRICTED_CAPABILITIES =
(1 << NET_CAPABILITY_CBS) |
(1 << NET_CAPABILITY_DUN) |
(1 << NET_CAPABILITY_EIMS) |
(1 << NET_CAPABILITY_FOTA) |
(1 << NET_CAPABILITY_IA) |
(1 << NET_CAPABILITY_IMS) |
(1 << NET_CAPABILITY_RCS) |
(1 << NET_CAPABILITY_XCAP);
/**
* Capabilities that suggest that a network is unrestricted.
* {@see #maybeMarkCapabilitiesRestricted}.
*/
@VisibleForTesting
/* package */ static final long UNRESTRICTED_CAPABILITIES =
(1 << NET_CAPABILITY_INTERNET) |
(1 << NET_CAPABILITY_MMS) |
(1 << NET_CAPABILITY_SUPL) |
(1 << NET_CAPABILITY_WIFI_P2P);
/**
* Adds the given capability to this {@code NetworkCapability} instance.
* Multiple capabilities may be applied sequentially. Note that when searching
* for a network to satisfy a request, all capabilities requested must be satisfied.
*
* @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
public NetworkCapabilities addCapability(int capability) {
if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
throw new IllegalArgumentException("NetworkCapability out of range");
}
mNetworkCapabilities |= 1 << capability;
return this;
}
/**
* Removes (if found) the given capability from this {@code NetworkCapability} instance.
*
* @param capability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
public NetworkCapabilities removeCapability(int capability) {
if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
throw new IllegalArgumentException("NetworkCapability out of range");
}
mNetworkCapabilities &= ~(1 << capability);
return this;
}
/**
* Gets all the capabilities set on this {@code NetworkCapability} instance.
*
* @return an array of {@code NetworkCapabilities.NET_CAPABILITY_*} values
* for this instance.
* @hide
*/
public int[] getCapabilities() {
return BitUtils.unpackBits(mNetworkCapabilities);
}
/**
* Tests for the presence of a capabilitity on this instance.
*
* @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for.
* @return {@code true} if set on this instance.
*/
public boolean hasCapability(int capability) {
if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) {
return false;
}
return ((mNetworkCapabilities & (1 << capability)) != 0);
}
private void combineNetCapabilities(NetworkCapabilities nc) {
this.mNetworkCapabilities |= nc.mNetworkCapabilities;
}
/**
* Convenience function that returns a human-readable description of the first mutable
* capability we find. Used to present an error message to apps that request mutable
* capabilities.
*
* @hide
*/
public String describeFirstNonRequestableCapability() {
if (hasCapability(NET_CAPABILITY_VALIDATED)) return "NET_CAPABILITY_VALIDATED";
if (hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return "NET_CAPABILITY_CAPTIVE_PORTAL";
if (hasCapability(NET_CAPABILITY_FOREGROUND)) return "NET_CAPABILITY_FOREGROUND";
// This cannot happen unless the preceding checks are incomplete.
if ((mNetworkCapabilities & NON_REQUESTABLE_CAPABILITIES) != 0) {
return "unknown non-requestable capabilities " + Long.toHexString(mNetworkCapabilities);
}
if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth";
if (hasSignalStrength()) return "signalStrength";
return null;
}
private boolean satisfiedByNetCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
long networkCapabilities = this.mNetworkCapabilities;
if (onlyImmutable) {
networkCapabilities = networkCapabilities & ~MUTABLE_CAPABILITIES;
}
return ((nc.mNetworkCapabilities & networkCapabilities) == networkCapabilities);
}
/** @hide */
public boolean equalsNetCapabilities(NetworkCapabilities nc) {
return (nc.mNetworkCapabilities == this.mNetworkCapabilities);
}
private boolean equalsNetCapabilitiesRequestable(NetworkCapabilities that) {
return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
(that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES));
}
/**
* Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are
* typically provided by restricted networks.
*
* TODO: consider:
* - Renaming it to guessRestrictedCapability and make it set the
* restricted capability bit in addition to clearing it.
* @hide
*/
public void maybeMarkCapabilitiesRestricted() {
// Verify there aren't any unrestricted capabilities. If there are we say
// the whole thing is unrestricted.
final boolean hasUnrestrictedCapabilities =
((mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0);
// Must have at least some restricted capabilities.
final boolean hasRestrictedCapabilities =
((mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0);
if (hasRestrictedCapabilities && !hasUnrestrictedCapabilities) {
removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
}
}
/**
* Representing the transport type. Apps should generally not care about transport. A
* request for a fast internet connection could be satisfied by a number of different
* transports. If any are specified here it will be satisfied a Network that matches
* any of them. If a caller doesn't care about the transport it should not specify any.
*/
private long mTransportTypes;
/**
* Indicates this network uses a Cellular transport.
*/
public static final int TRANSPORT_CELLULAR = 0;
/**
* Indicates this network uses a Wi-Fi transport.
*/
public static final int TRANSPORT_WIFI = 1;
/**
* Indicates this network uses a Bluetooth transport.
*/
public static final int TRANSPORT_BLUETOOTH = 2;
/**
* Indicates this network uses an Ethernet transport.
*/
public static final int TRANSPORT_ETHERNET = 3;
/**
* Indicates this network uses a VPN transport.
*/
public static final int TRANSPORT_VPN = 4;
/**
* Indicates this network uses a Wi-Fi Aware transport.
*/
public static final int TRANSPORT_WIFI_AWARE = 5;
/**
* Indicates this network uses a LoWPAN transport.
*/
public static final int TRANSPORT_LOWPAN = 6;
/** @hide */
public static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
/** @hide */
public static final int MAX_TRANSPORT = TRANSPORT_LOWPAN;
/** @hide */
public static boolean isValidTransport(int transportType) {
return (MIN_TRANSPORT <= transportType) && (transportType <= MAX_TRANSPORT);
}
private static final String[] TRANSPORT_NAMES = {
"CELLULAR",
"WIFI",
"BLUETOOTH",
"ETHERNET",
"VPN",
"WIFI_AWARE",
"LOWPAN"
};
/**
* Adds the given transport type to this {@code NetworkCapability} instance.
* Multiple transports may be applied sequentially. Note that when searching
* for a network to satisfy a request, any listed in the request will satisfy the request.
* For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
* {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
* to be selected. This is logically different than
* {@code NetworkCapabilities.NET_CAPABILITY_*} listed above.
*
* @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
public NetworkCapabilities addTransportType(int transportType) {
checkValidTransportType(transportType);
mTransportTypes |= 1 << transportType;
setNetworkSpecifier(mNetworkSpecifier); // used for exception checking
return this;
}
/**
* Removes (if found) the given transport from this {@code NetworkCapability} instance.
*
* @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
public NetworkCapabilities removeTransportType(int transportType) {
checkValidTransportType(transportType);
mTransportTypes &= ~(1 << transportType);
setNetworkSpecifier(mNetworkSpecifier); // used for exception checking
return this;
}
/**
* Gets all the transports set on this {@code NetworkCapability} instance.
*
* @return an array of {@code NetworkCapabilities.TRANSPORT_*} values
* for this instance.
* @hide
*/
public int[] getTransportTypes() {
return BitUtils.unpackBits(mTransportTypes);
}
/**
* Tests for the presence of a transport on this instance.
*
* @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be tested for.
* @return {@code true} if set on this instance.
*/
public boolean hasTransport(int transportType) {
return isValidTransport(transportType) && ((mTransportTypes & (1 << transportType)) != 0);
}
private void combineTransportTypes(NetworkCapabilities nc) {
this.mTransportTypes |= nc.mTransportTypes;
}
private boolean satisfiedByTransportTypes(NetworkCapabilities nc) {
return ((this.mTransportTypes == 0) ||
((this.mTransportTypes & nc.mTransportTypes) != 0));
}
/** @hide */
public boolean equalsTransportTypes(NetworkCapabilities nc) {
return (nc.mTransportTypes == this.mTransportTypes);
}
/**
* Passive link bandwidth. This is a rough guide of the expected peak bandwidth
* for the first hop on the given transport. It is not measured, but may take into account
* link parameters (Radio technology, allocated channels, etc).
*/
private int mLinkUpBandwidthKbps;
private int mLinkDownBandwidthKbps;
/**
* Sets the upstream bandwidth for this network in Kbps. This always only refers to
* the estimated first hop transport bandwidth.
* <p>
* Note that when used to request a network, this specifies the minimum acceptable.
* When received as the state of an existing network this specifies the typical
* first hop bandwidth expected. This is never measured, but rather is inferred
* from technology type and other link parameters. It could be used to differentiate
* between very slow 1xRTT cellular links and other faster networks or even between
* 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
* fast backhauls and slow backhauls.
*
* @param upKbps the estimated first hop upstream (device to network) bandwidth.
* @hide
*/
public void setLinkUpstreamBandwidthKbps(int upKbps) {
mLinkUpBandwidthKbps = upKbps;
}
/**
* Retrieves the upstream bandwidth for this network in Kbps. This always only refers to
* the estimated first hop transport bandwidth.
*
* @return The estimated first hop upstream (device to network) bandwidth.
*/
public int getLinkUpstreamBandwidthKbps() {
return mLinkUpBandwidthKbps;
}
/**
* Sets the downstream bandwidth for this network in Kbps. This always only refers to
* the estimated first hop transport bandwidth.
* <p>
* Note that when used to request a network, this specifies the minimum acceptable.
* When received as the state of an existing network this specifies the typical
* first hop bandwidth expected. This is never measured, but rather is inferred
* from technology type and other link parameters. It could be used to differentiate
* between very slow 1xRTT cellular links and other faster networks or even between
* 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
* fast backhauls and slow backhauls.
*
* @param downKbps the estimated first hop downstream (network to device) bandwidth.
* @hide
*/
public void setLinkDownstreamBandwidthKbps(int downKbps) {
mLinkDownBandwidthKbps = downKbps;
}
/**
* Retrieves the downstream bandwidth for this network in Kbps. This always only refers to
* the estimated first hop transport bandwidth.
*
* @return The estimated first hop downstream (network to device) bandwidth.
*/
public int getLinkDownstreamBandwidthKbps() {
return mLinkDownBandwidthKbps;
}
private void combineLinkBandwidths(NetworkCapabilities nc) {
this.mLinkUpBandwidthKbps =
Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps);
this.mLinkDownBandwidthKbps =
Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps);
}
private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) {
return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps ||
this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps);
}
private boolean equalsLinkBandwidths(NetworkCapabilities nc) {
return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps &&
this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps);
}
private NetworkSpecifier mNetworkSpecifier = null;
/**
* Sets the optional bearer specific network specifier.
* This has no meaning if a single transport is also not specified, so calling
* this without a single transport set will generate an exception, as will
* subsequently adding or removing transports after this is set.
* </p>
*
* @param networkSpecifier A concrete, parcelable framework class that extends
* NetworkSpecifier.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
public NetworkCapabilities setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
if (networkSpecifier != null && Long.bitCount(mTransportTypes) != 1) {
throw new IllegalStateException("Must have a single transport specified to use " +
"setNetworkSpecifier");
}
mNetworkSpecifier = networkSpecifier;
return this;
}
/**
* Gets the optional bearer specific network specifier.
*
* @return The optional {@link NetworkSpecifier} specifying the bearer specific network
* specifier. See {@link #setNetworkSpecifier}.
* @hide
*/
public NetworkSpecifier getNetworkSpecifier() {
return mNetworkSpecifier;
}
private void combineSpecifiers(NetworkCapabilities nc) {
if (mNetworkSpecifier != null && !mNetworkSpecifier.equals(nc.mNetworkSpecifier)) {
throw new IllegalStateException("Can't combine two networkSpecifiers");
}
setNetworkSpecifier(nc.mNetworkSpecifier);
}
private boolean satisfiedBySpecifier(NetworkCapabilities nc) {
return mNetworkSpecifier == null || mNetworkSpecifier.satisfiedBy(nc.mNetworkSpecifier)
|| nc.mNetworkSpecifier instanceof MatchAllNetworkSpecifier;
}
private boolean equalsSpecifier(NetworkCapabilities nc) {
return Objects.equals(mNetworkSpecifier, nc.mNetworkSpecifier);
}
/**
* Magic value that indicates no signal strength provided. A request specifying this value is
* always satisfied.
*
* @hide
*/
public static final int SIGNAL_STRENGTH_UNSPECIFIED = Integer.MIN_VALUE;
/**
* Signal strength. This is a signed integer, and higher values indicate better signal.
* The exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
*/
private int mSignalStrength;
/**
* Sets the signal strength. This is a signed integer, with higher values indicating a stronger
* signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same RSSI units
* reported by WifiManager.
* <p>
* Note that when used to register a network callback, this specifies the minimum acceptable
* signal strength. When received as the state of an existing network it specifies the current
* value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means no value when received and has no
* effect when requesting a callback.
*
* @param signalStrength the bearer-specific signal strength.
* @hide
*/
public void setSignalStrength(int signalStrength) {
mSignalStrength = signalStrength;
}
/**
* Returns {@code true} if this object specifies a signal strength.
*
* @hide
*/
public boolean hasSignalStrength() {
return mSignalStrength > SIGNAL_STRENGTH_UNSPECIFIED;
}
/**
* Retrieves the signal strength.
*
* @return The bearer-specific signal strength.
* @hide
*/
public int getSignalStrength() {
return mSignalStrength;
}
private void combineSignalStrength(NetworkCapabilities nc) {
this.mSignalStrength = Math.max(this.mSignalStrength, nc.mSignalStrength);
}
private boolean satisfiedBySignalStrength(NetworkCapabilities nc) {
return this.mSignalStrength <= nc.mSignalStrength;
}
private boolean equalsSignalStrength(NetworkCapabilities nc) {
return this.mSignalStrength == nc.mSignalStrength;
}
/**
* Combine a set of Capabilities to this one. Useful for coming up with the complete set
* @hide
*/
public void combineCapabilities(NetworkCapabilities nc) {
combineNetCapabilities(nc);
combineTransportTypes(nc);
combineLinkBandwidths(nc);
combineSpecifiers(nc);
combineSignalStrength(nc);
}
/**
* Check if our requirements are satisfied by the given {@code NetworkCapabilities}.
*
* @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements.
* @param onlyImmutable if {@code true}, do not consider mutable requirements such as link
* bandwidth, signal strength, or validation / captive portal status.
*
* @hide
*/
private boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
return (nc != null &&
satisfiedByNetCapabilities(nc, onlyImmutable) &&
satisfiedByTransportTypes(nc) &&
(onlyImmutable || satisfiedByLinkBandwidths(nc)) &&
satisfiedBySpecifier(nc) &&
(onlyImmutable || satisfiedBySignalStrength(nc)));
}
/**
* Check if our requirements are satisfied by the given {@code NetworkCapabilities}.
*
* @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements.
*
* @hide
*/
public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) {
return satisfiedByNetworkCapabilities(nc, false);
}
/**
* Check if our immutable requirements are satisfied by the given {@code NetworkCapabilities}.
*
* @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements.
*
* @hide
*/
public boolean satisfiedByImmutableNetworkCapabilities(NetworkCapabilities nc) {
return satisfiedByNetworkCapabilities(nc, true);
}
/**
* Checks that our immutable capabilities are the same as those of the given
* {@code NetworkCapabilities} and return a String describing any difference.
* The returned String is empty if there is no difference.
*
* @hide
*/
public String describeImmutableDifferences(NetworkCapabilities that) {
if (that == null) {
return "other NetworkCapabilities was null";
}
StringJoiner joiner = new StringJoiner(", ");
// Ignore NOT_METERED being added or removed as it is effectively dynamic. http://b/63326103
// TODO: properly support NOT_METERED as a mutable and requestable capability.
// Ignore DUN being added or removed. http://b/65257223.
final long mask = ~MUTABLE_CAPABILITIES
& ~(1 << NET_CAPABILITY_NOT_METERED) & ~(1 << NET_CAPABILITY_DUN);
long oldImmutableCapabilities = this.mNetworkCapabilities & mask;
long newImmutableCapabilities = that.mNetworkCapabilities & mask;
if (oldImmutableCapabilities != newImmutableCapabilities) {
String before = capabilityNamesOf(BitUtils.unpackBits(oldImmutableCapabilities));
String after = capabilityNamesOf(BitUtils.unpackBits(newImmutableCapabilities));
joiner.add(String.format("immutable capabilities changed: %s -> %s", before, after));
}
if (!equalsSpecifier(that)) {
NetworkSpecifier before = this.getNetworkSpecifier();
NetworkSpecifier after = that.getNetworkSpecifier();
joiner.add(String.format("specifier changed: %s -> %s", before, after));
}
if (!equalsTransportTypes(that)) {
String before = transportNamesOf(this.getTransportTypes());
String after = transportNamesOf(that.getTransportTypes());
joiner.add(String.format("transports changed: %s -> %s", before, after));
}
return joiner.toString();
}
/**
* Checks that our requestable capabilities are the same as those of the given
* {@code NetworkCapabilities}.
*
* @hide
*/
public boolean equalRequestableCapabilities(NetworkCapabilities nc) {
if (nc == null) return false;
return (equalsNetCapabilitiesRequestable(nc) &&
equalsTransportTypes(nc) &&
equalsSpecifier(nc));
}
@Override
public boolean equals(Object obj) {
if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
NetworkCapabilities that = (NetworkCapabilities)obj;
return (equalsNetCapabilities(that) &&
equalsTransportTypes(that) &&
equalsLinkBandwidths(that) &&
equalsSignalStrength(that) &&
equalsSpecifier(that));
}
@Override
public int hashCode() {
return ((int)(mNetworkCapabilities & 0xFFFFFFFF) +
((int)(mNetworkCapabilities >> 32) * 3) +
((int)(mTransportTypes & 0xFFFFFFFF) * 5) +
((int)(mTransportTypes >> 32) * 7) +
(mLinkUpBandwidthKbps * 11) +
(mLinkDownBandwidthKbps * 13) +
Objects.hashCode(mNetworkSpecifier) * 17 +
(mSignalStrength * 19));
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(mNetworkCapabilities);
dest.writeLong(mTransportTypes);
dest.writeInt(mLinkUpBandwidthKbps);
dest.writeInt(mLinkDownBandwidthKbps);
dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
dest.writeInt(mSignalStrength);
}
public static final Creator<NetworkCapabilities> CREATOR =
new Creator<NetworkCapabilities>() {
@Override
public NetworkCapabilities createFromParcel(Parcel in) {
NetworkCapabilities netCap = new NetworkCapabilities();
netCap.mNetworkCapabilities = in.readLong();
netCap.mTransportTypes = in.readLong();
netCap.mLinkUpBandwidthKbps = in.readInt();
netCap.mLinkDownBandwidthKbps = in.readInt();
netCap.mNetworkSpecifier = in.readParcelable(null);
netCap.mSignalStrength = in.readInt();
return netCap;
}
@Override
public NetworkCapabilities[] newArray(int size) {
return new NetworkCapabilities[size];
}
};
@Override
public String toString() {
// TODO: enumerate bits for transports and capabilities instead of creating arrays.
// TODO: use a StringBuilder instead of string concatenation.
int[] types = getTransportTypes();
String transports = (types.length > 0) ? " Transports: " + transportNamesOf(types) : "";
types = getCapabilities();
String capabilities = (types.length > 0 ? " Capabilities: " : "");
for (int i = 0; i < types.length; ) {
capabilities += capabilityNameOf(types[i]);
if (++i < types.length) capabilities += "&";
}
String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" +
mLinkUpBandwidthKbps + "Kbps" : "");
String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" +
mLinkDownBandwidthKbps + "Kbps" : "");
String specifier = (mNetworkSpecifier == null ?
"" : " Specifier: <" + mNetworkSpecifier + ">");
String signalStrength = (hasSignalStrength() ? " SignalStrength: " + mSignalStrength : "");
return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength + "]";
}
/**
* @hide
*/
public static String capabilityNamesOf(int[] capabilities) {
StringJoiner joiner = new StringJoiner("|");
if (capabilities != null) {
for (int c : capabilities) {
joiner.add(capabilityNameOf(c));
}
}
return joiner.toString();
}
/**
* @hide
*/
public static String capabilityNameOf(int capability) {
switch (capability) {
case NET_CAPABILITY_MMS: return "MMS";
case NET_CAPABILITY_SUPL: return "SUPL";
case NET_CAPABILITY_DUN: return "DUN";
case NET_CAPABILITY_FOTA: return "FOTA";
case NET_CAPABILITY_IMS: return "IMS";
case NET_CAPABILITY_CBS: return "CBS";
case NET_CAPABILITY_WIFI_P2P: return "WIFI_P2P";
case NET_CAPABILITY_IA: return "IA";
case NET_CAPABILITY_RCS: return "RCS";
case NET_CAPABILITY_XCAP: return "XCAP";
case NET_CAPABILITY_EIMS: return "EIMS";
case NET_CAPABILITY_NOT_METERED: return "NOT_METERED";
case NET_CAPABILITY_INTERNET: return "INTERNET";
case NET_CAPABILITY_NOT_RESTRICTED: return "NOT_RESTRICTED";
case NET_CAPABILITY_TRUSTED: return "TRUSTED";
case NET_CAPABILITY_NOT_VPN: return "NOT_VPN";
case NET_CAPABILITY_VALIDATED: return "VALIDATED";
case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL";
case NET_CAPABILITY_FOREGROUND: return "FOREGROUND";
default: return Integer.toString(capability);
}
}
/**
* @hide
*/
public static String transportNamesOf(int[] types) {
StringJoiner joiner = new StringJoiner("|");
if (types != null) {
for (int t : types) {
joiner.add(transportNameOf(t));
}
}
return joiner.toString();
}
/**
* @hide
*/
public static String transportNameOf(int transport) {
if (!isValidTransport(transport)) {
return "UNKNOWN";
}
return TRANSPORT_NAMES[transport];
}
private static void checkValidTransportType(int transport) {
Preconditions.checkArgument(
isValidTransport(transport), "Invalid TransportType " + transport);
}
}
|