1 /* 2 * Copyright 2021 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 com.android.internal.telephony.data; 18 19 import android.annotation.ElapsedRealtimeLong; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.net.NetworkCapabilities; 24 import android.net.NetworkRequest; 25 import android.net.NetworkSpecifier; 26 import android.os.SystemClock; 27 import android.telephony.Annotation.ConnectivityTransport; 28 import android.telephony.Annotation.NetCapability; 29 import android.telephony.data.ApnSetting; 30 import android.telephony.data.DataProfile; 31 import android.telephony.data.TrafficDescriptor; 32 import android.telephony.data.TrafficDescriptor.OsAppId; 33 34 import com.android.internal.telephony.Phone; 35 import com.android.internal.telephony.flags.FeatureFlags; 36 37 import java.lang.annotation.Retention; 38 import java.lang.annotation.RetentionPolicy; 39 import java.util.AbstractMap.SimpleImmutableEntry; 40 import java.util.Arrays; 41 import java.util.Comparator; 42 import java.util.List; 43 import java.util.Map; 44 import java.util.stream.Collectors; 45 46 /** 47 * TelephonyNetworkRequest is a wrapper class on top of {@link NetworkRequest}, which is originated 48 * from the apps to request network. This class is intended to track supplemental information 49 * related to this request, for example priority, evaluation result, whether this request is 50 * actively being satisfied, timestamp, etc... 51 * 52 */ 53 public class TelephonyNetworkRequest { 54 @Retention(RetentionPolicy.SOURCE) 55 @IntDef(prefix = {"REQUEST_STATE_"}, 56 value = { 57 REQUEST_STATE_UNSATISFIED, 58 REQUEST_STATE_SATISFIED}) 59 public @interface RequestState {} 60 61 /** 62 * Indicating currently no data networks can satisfy this network request. 63 */ 64 public static final int REQUEST_STATE_UNSATISFIED = 0; 65 66 /** 67 * Indicating this request is already satisfied. It must have an attached network (which could 68 * be in any state, including disconnecting). Also note this does not mean the network request 69 * is satisfied in telephony layer. Whether the network request is finally satisfied or not is 70 * determined at the connectivity service layer. 71 */ 72 public static final int REQUEST_STATE_SATISFIED = 1; 73 74 /** @hide */ 75 @IntDef(flag = true, prefix = { "CAPABILITY_ATTRIBUTE_" }, value = { 76 CAPABILITY_ATTRIBUTE_NONE, 77 CAPABILITY_ATTRIBUTE_APN_SETTING, 78 CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN, 79 CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID, 80 }) 81 @Retention(RetentionPolicy.SOURCE) 82 public @interface NetCapabilityAttribute {} 83 84 /** Network capability attribute none. */ 85 public static final int CAPABILITY_ATTRIBUTE_NONE = 0; 86 87 /** 88 * The network capability should result in filling {@link ApnSetting} in {@link DataProfile}. 89 */ 90 public static final int CAPABILITY_ATTRIBUTE_APN_SETTING = 1; 91 92 /** The network capability should result in filling DNN in {@link TrafficDescriptor}. */ 93 public static final int CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN = 1 << 1; 94 95 /** The network capability should result in filling OS/APP id in {@link TrafficDescriptor}. */ 96 public static final int CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID = 1 << 2; 97 98 /** 99 * Describes the attributes of network capabilities. Different capabilities can be translated 100 * to different fields in {@link DataProfile}, or might be expanded to support special actions 101 * in telephony in the future. 102 */ 103 private static final Map<Integer, Integer> CAPABILITY_ATTRIBUTE_MAP = Map.ofEntries( 104 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_MMS, 105 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 106 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_SUPL, 107 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 108 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_DUN, 109 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 110 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_FOTA, 111 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 112 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_IMS, 113 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 114 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_CBS, 115 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN 116 | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID), 117 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_XCAP, 118 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 119 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_EIMS, 120 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 121 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_INTERNET, 122 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 123 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_MCX, 124 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 125 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE, 126 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN 127 | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID), 128 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_VSIM, 129 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 130 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_BIP, 131 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN), 132 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY, 133 CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID), 134 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH, 135 CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID), 136 new SimpleImmutableEntry<>(NetworkCapabilities.NET_CAPABILITY_RCS, 137 CAPABILITY_ATTRIBUTE_APN_SETTING | CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN) 138 ); 139 140 /** The phone instance. */ 141 @NonNull 142 private final Phone mPhone; 143 144 /** 145 * Native network request from the clients. See {@link NetworkRequest}; 146 */ 147 @NonNull 148 private final NetworkRequest mNativeNetworkRequest; 149 150 /** 151 * The attributes of the network capabilities in this network request. This describes how this 152 * network request can be translated to different fields in {@link DataProfile} or perform 153 * special actions in telephony. 154 */ 155 @NetCapabilityAttribute 156 private final int mCapabilitiesAttributes; 157 158 /** 159 * Priority of the network request. The network request has higher priority will be satisfied 160 * first than lower priority ones. 161 */ 162 private int mPriority; 163 164 /** 165 * Data config manager for retrieving data config. 166 */ 167 @NonNull 168 private final DataConfigManager mDataConfigManager; 169 170 /** 171 * The attached data network. Note that the data network could be in any state. {@code null} 172 * indicates this network request is not satisfied. 173 */ 174 @Nullable 175 private DataNetwork mAttachedDataNetwork; 176 177 /** 178 * The state of the network request. 179 * 180 * @see #REQUEST_STATE_UNSATISFIED 181 * @see #REQUEST_STATE_SATISFIED 182 */ 183 // This is not a boolean because there might be more states in the future. 184 @RequestState 185 private int mState; 186 187 /** The timestamp when this network request enters telephony. */ 188 @ElapsedRealtimeLong 189 private final long mCreatedTimeMillis; 190 191 /** The data evaluation result. */ 192 @Nullable 193 private DataEvaluation mEvaluation; 194 195 /** Feature flag. */ 196 @NonNull 197 private final FeatureFlags mFeatureFlags; 198 199 /** 200 * Constructor 201 * 202 * @param request The native network request from the clients. 203 * @param phone The phone instance 204 * @param featureFlags The feature flag 205 */ TelephonyNetworkRequest(@onNull NetworkRequest request, @NonNull Phone phone, @NonNull FeatureFlags featureFlags)206 public TelephonyNetworkRequest(@NonNull NetworkRequest request, @NonNull Phone phone, 207 @NonNull FeatureFlags featureFlags) { 208 mPhone = phone; 209 mNativeNetworkRequest = request; 210 mFeatureFlags = featureFlags; 211 212 int capabilitiesAttributes = CAPABILITY_ATTRIBUTE_NONE; 213 for (int networkCapability : mNativeNetworkRequest.getCapabilities()) { 214 capabilitiesAttributes |= CAPABILITY_ATTRIBUTE_MAP.getOrDefault( 215 networkCapability, CAPABILITY_ATTRIBUTE_NONE); 216 } 217 mCapabilitiesAttributes = capabilitiesAttributes; 218 219 mPriority = 0; 220 mAttachedDataNetwork = null; 221 // When the request was first created, it is in active state so we can actively attempt 222 // to satisfy it. 223 mState = REQUEST_STATE_UNSATISFIED; 224 mCreatedTimeMillis = SystemClock.elapsedRealtime(); 225 mDataConfigManager = phone.getDataNetworkController().getDataConfigManager(); 226 updatePriority(); 227 } 228 229 /** 230 * @see NetworkRequest#getNetworkSpecifier() 231 */ 232 @Nullable getNetworkSpecifier()233 public NetworkSpecifier getNetworkSpecifier() { 234 return mNativeNetworkRequest.getNetworkSpecifier(); 235 } 236 237 /** 238 * @see NetworkRequest#getCapabilities() 239 */ 240 @NonNull 241 @NetCapability getCapabilities()242 public int[] getCapabilities() { 243 return mNativeNetworkRequest.getCapabilities(); 244 } 245 246 /** 247 * @see NetworkRequest#hasCapability(int) 248 */ hasCapability(@etCapability int capability)249 public boolean hasCapability(@NetCapability int capability) { 250 return mNativeNetworkRequest.hasCapability(capability); 251 } 252 253 /** 254 * @see NetworkRequest#getTransportTypes() 255 */ 256 @NonNull 257 @ConnectivityTransport getTransportTypes()258 public int[] getTransportTypes() { 259 return mNativeNetworkRequest.getTransportTypes(); 260 } 261 262 /** 263 * @return {@code true} if the request can be served on the specified transport. 264 * @see NetworkRequest#hasTransport 265 */ hasTransport(@onnectivityTransport int transport)266 public boolean hasTransport(@ConnectivityTransport int transport) { 267 return mNativeNetworkRequest.hasTransport(transport); 268 } 269 270 /** 271 * @see NetworkRequest#canBeSatisfiedBy(NetworkCapabilities) 272 */ canBeSatisfiedBy(@ullable NetworkCapabilities nc)273 public boolean canBeSatisfiedBy(@Nullable NetworkCapabilities nc) { 274 return mNativeNetworkRequest.canBeSatisfiedBy(nc); 275 } 276 277 278 /** 279 * Check if the request's capabilities have certain attributes. 280 * 281 * @param capabilitiesAttributes The attributes to check. 282 * @return {@code true} if the capabilities have provided attributes. 283 * 284 * @see NetCapabilityAttribute 285 */ hasAttribute(@etCapabilityAttribute int capabilitiesAttributes)286 public boolean hasAttribute(@NetCapabilityAttribute int capabilitiesAttributes) { 287 return (mCapabilitiesAttributes & capabilitiesAttributes) == capabilitiesAttributes; 288 } 289 290 /** 291 * Check if this network request can be satisfied by a data profile. 292 * 293 * @param dataProfile The data profile to check. 294 * @return {@code true} if this network request can be satisfied by the data profile. 295 */ canBeSatisfiedBy(@onNull DataProfile dataProfile)296 public boolean canBeSatisfiedBy(@NonNull DataProfile dataProfile) { 297 // If the network request can be translated to OS/App id, then check if the data profile's 298 // OS/App id can satisfy it. 299 if (hasAttribute(CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID) 300 && getOsAppId() != null) { 301 // The network request has traffic descriptor type capabilities. Match the traffic 302 // descriptor. 303 if (dataProfile.getTrafficDescriptor() != null && Arrays.equals(getOsAppId().getBytes(), 304 dataProfile.getTrafficDescriptor().getOsAppId())) { 305 return true; 306 } 307 } 308 309 // If the network request can be translated to APN setting or DNN in traffic descriptor, 310 // then check if the data profile's APN setting can satisfy it. 311 if ((hasAttribute(CAPABILITY_ATTRIBUTE_APN_SETTING) 312 || hasAttribute(CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN)) 313 && dataProfile.getApnSetting() != null) { 314 if (mFeatureFlags.satelliteInternet()) { 315 if (mNativeNetworkRequest.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) 316 && !mNativeNetworkRequest.hasTransport( 317 NetworkCapabilities.TRANSPORT_SATELLITE)) { 318 if (Arrays.stream(getCapabilities()).noneMatch(mDataConfigManager 319 .getForcedCellularTransportCapabilities()::contains)) { 320 // If the request is explicitly for the cellular, then the data profile 321 // needs to support cellular. 322 if (!dataProfile.getApnSetting().isForInfrastructure( 323 ApnSetting.INFRASTRUCTURE_CELLULAR)) { 324 return false; 325 } 326 } 327 } else if (mNativeNetworkRequest.hasTransport( 328 NetworkCapabilities.TRANSPORT_SATELLITE) 329 && !mNativeNetworkRequest.hasTransport( 330 NetworkCapabilities.TRANSPORT_CELLULAR)) { 331 // If the request is explicitly for the satellite, then the data profile needs 332 // to support satellite. 333 if (!dataProfile.getApnSetting().isForInfrastructure( 334 ApnSetting.INFRASTRUCTURE_SATELLITE)) { 335 return false; 336 } 337 } 338 } 339 // Fallback to the legacy APN type matching. 340 List<Integer> apnTypes = Arrays.stream(getCapabilities()).boxed() 341 .map(DataUtils::networkCapabilityToApnType) 342 .filter(apnType -> apnType != ApnSetting.TYPE_NONE) 343 .collect(Collectors.toList()); 344 // In case of enterprise network request, the network request will have internet, 345 // but APN type will not have default type as the enterprise apn should not be used 346 // as default network. Ignore default type of the network request if it 347 // has enterprise type as well. This will make sure the network request with 348 // internet and enterprise will be satisfied with data profile with enterprise at the 349 // same time default network request will not get satisfied with enterprise data 350 // profile. 351 // TODO b/232264746 352 if (apnTypes.contains(ApnSetting.TYPE_ENTERPRISE)) { 353 apnTypes.remove((Integer) ApnSetting.TYPE_DEFAULT); 354 } 355 356 return apnTypes.stream().allMatch(dataProfile.getApnSetting()::canHandleType); 357 } 358 return false; 359 } 360 361 /** 362 * Get the priority of the network request. 363 * 364 * @return The priority from 0 to 100. 100 indicates the highest priority. 365 */ getPriority()366 public int getPriority() { 367 return mPriority; 368 } 369 370 /** 371 * Update the priority from data config manager. 372 */ updatePriority()373 public void updatePriority() { 374 mPriority = Arrays.stream(mNativeNetworkRequest.getCapabilities()) 375 .map(mDataConfigManager::getNetworkCapabilityPriority) 376 .max() 377 .orElse(0); 378 } 379 380 /** 381 * Get the network capability which is APN-type based from the network request. If there are 382 * multiple APN types capability, the highest priority one will be returned. 383 * 384 * @return The highest priority APN type based network capability from this network request. -1 385 * if there is no APN type capabilities in this network request. 386 */ 387 @NetCapability getApnTypeNetworkCapability()388 public int getApnTypeNetworkCapability() { 389 if (!hasAttribute(CAPABILITY_ATTRIBUTE_APN_SETTING)) return -1; 390 return Arrays.stream(getCapabilities()).boxed() 391 .filter(cap -> DataUtils.networkCapabilityToApnType(cap) != ApnSetting.TYPE_NONE) 392 .max(Comparator.comparingInt(mDataConfigManager::getNetworkCapabilityPriority)) 393 .orElse(-1); 394 } 395 /** 396 * @return The native network request. 397 */ 398 @NonNull getNativeNetworkRequest()399 public NetworkRequest getNativeNetworkRequest() { 400 return mNativeNetworkRequest; 401 } 402 403 /** 404 * Set the attached data network. 405 * 406 * @param dataNetwork The data network. 407 */ setAttachedNetwork(@ullable DataNetwork dataNetwork)408 public void setAttachedNetwork(@Nullable DataNetwork dataNetwork) { 409 mAttachedDataNetwork = dataNetwork; 410 } 411 412 /** 413 * @return The attached network. {@code null} indicates the request is not attached to any 414 * network (i.e. the request is unsatisfied). 415 */ 416 @Nullable getAttachedNetwork()417 public DataNetwork getAttachedNetwork() { 418 return mAttachedDataNetwork; 419 } 420 421 /** 422 * Set the state of the network request. 423 * 424 * @param state The state. 425 */ setState(@equestState int state)426 public void setState(@RequestState int state) { 427 mState = state; 428 } 429 430 /** 431 * @return The state of the network request. 432 */ 433 @RequestState getState()434 public int getState() { 435 return mState; 436 } 437 438 /** 439 * Set the data evaluation result. 440 * 441 * @param evaluation The data evaluation result. 442 */ setEvaluation(@onNull DataEvaluation evaluation)443 public void setEvaluation(@NonNull DataEvaluation evaluation) { 444 mEvaluation = evaluation; 445 } 446 447 /** 448 * Get the capability differentiator from the network request. Some capabilities 449 * (e.g. {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE} could support more than one 450 * traffic (e.g. "ENTERPRISE2", "ENTERPRISE3"). This method returns that differentiator. 451 * 452 * @return The differentiator. 0 if not found. 453 */ getCapabilityDifferentiator()454 public int getCapabilityDifferentiator() { 455 if (hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)) { 456 int[] ids = mNativeNetworkRequest.getEnterpriseIds(); 457 // No need to verify the range of the id. It has been done in NetworkCapabilities. 458 if (ids.length > 0) return ids[0]; 459 } 460 return 0; 461 } 462 463 /** 464 * @return {@code true} if this network request can result in bringing up a metered network. 465 */ isMeteredRequest()466 public boolean isMeteredRequest() { 467 return mDataConfigManager.isAnyMeteredCapability( 468 getCapabilities(), mPhone.getServiceState().getDataRoaming()); 469 } 470 471 /** 472 * Get Os/App id from the network request. 473 * 474 * @return Os/App id. {@code null} if the request does not have traffic descriptor based network 475 * capabilities. 476 */ 477 @Nullable getOsAppId()478 public OsAppId getOsAppId() { 479 if (!hasAttribute(CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID)) return null; 480 481 // We do not support multiple network capabilities translated to Os/App id at this time. 482 // If someday this needs to be done, we need to expand TrafficDescriptor to support 483 // connection capabilities instead of using Os/App id to do the work. 484 int networkCapability = Arrays.stream(getCapabilities()).boxed() 485 .filter(cap -> (CAPABILITY_ATTRIBUTE_MAP.getOrDefault( 486 cap, CAPABILITY_ATTRIBUTE_NONE) 487 & CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID) != 0) 488 .findFirst() 489 .orElse(-1); 490 491 if (networkCapability == -1) return null; 492 493 int differentiator = getCapabilityDifferentiator(); 494 if (differentiator > 0) { 495 return new OsAppId(OsAppId.ANDROID_OS_ID, 496 DataUtils.networkCapabilityToString(networkCapability), differentiator); 497 } else { 498 return new OsAppId(OsAppId.ANDROID_OS_ID, 499 DataUtils.networkCapabilityToString(networkCapability)); 500 } 501 } 502 503 /** 504 * Convert the telephony request state to string. 505 * 506 * @param state The request state. 507 * @return The request state in string format. 508 */ 509 @NonNull requestStateToString( @elephonyNetworkRequest.RequestState int state)510 private static String requestStateToString( 511 @TelephonyNetworkRequest.RequestState int state) { 512 return switch (state) { 513 case TelephonyNetworkRequest.REQUEST_STATE_UNSATISFIED -> "UNSATISFIED"; 514 case TelephonyNetworkRequest.REQUEST_STATE_SATISFIED -> "SATISFIED"; 515 default -> "UNKNOWN(" + state + ")"; 516 }; 517 } 518 519 @Override toString()520 public String toString() { 521 return "[" + mNativeNetworkRequest + ", mPriority=" + mPriority 522 + ", state=" + requestStateToString(mState) 523 + ", mAttachedDataNetwork=" + (mAttachedDataNetwork != null 524 ? mAttachedDataNetwork.name() : null) + ", isMetered=" + isMeteredRequest() 525 + ", created time=" + DataUtils.elapsedTimeToString(mCreatedTimeMillis) 526 + ", evaluation result=" + mEvaluation + "]"; 527 } 528 529 @Override equals(Object o)530 public boolean equals(Object o) { 531 if (this == o) return true; 532 if (o == null || getClass() != o.getClass()) return false; 533 TelephonyNetworkRequest that = (TelephonyNetworkRequest) o; 534 // Only compare the native network request. 535 return mNativeNetworkRequest.equals(that.mNativeNetworkRequest); 536 } 537 538 @Override hashCode()539 public int hashCode() { 540 // Only use the native network request's hash code. 541 return mNativeNetworkRequest.hashCode(); 542 } 543 } 544