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