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