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.CallbackExecutor;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.content.ContentResolver;
23 import android.content.ContentValues;
24 import android.database.ContentObserver;
25 import android.database.Cursor;
26 import android.net.NetworkCapabilities;
27 import android.net.NetworkRequest;
28 import android.net.Uri;
29 import android.os.Handler;
30 import android.os.Looper;
31 import android.os.Message;
32 import android.provider.Telephony;
33 import android.telephony.Annotation;
34 import android.telephony.Annotation.NetworkType;
35 import android.telephony.AnomalyReporter;
36 import android.telephony.CarrierConfigManager;
37 import android.telephony.NetworkRegistrationInfo;
38 import android.telephony.SubscriptionManager;
39 import android.telephony.TelephonyManager;
40 import android.telephony.TelephonyManager.SimState;
41 import android.telephony.data.ApnSetting;
42 import android.telephony.data.DataProfile;
43 import android.telephony.data.TrafficDescriptor;
44 import android.text.TextUtils;
45 import android.util.ArraySet;
46 import android.util.IndentingPrintWriter;
47 import android.util.LocalLog;
48 import android.util.LruCache;
49 
50 import com.android.internal.telephony.Phone;
51 import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback;
52 import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
53 import com.android.internal.telephony.flags.FeatureFlags;
54 import com.android.telephony.Rlog;
55 
56 import java.io.FileDescriptor;
57 import java.io.PrintWriter;
58 import java.util.ArrayList;
59 import java.util.Comparator;
60 import java.util.List;
61 import java.util.Objects;
62 import java.util.Set;
63 import java.util.UUID;
64 import java.util.concurrent.Executor;
65 import java.util.stream.Collectors;
66 
67 /**
68  * DataProfileManager manages the all {@link DataProfile}s for the current
69  * subscription.
70  */
71 public class DataProfileManager extends Handler {
72     private static final boolean VDBG = true;
73 
74     /** Event for APN database changed. */
75     private static final int EVENT_APN_DATABASE_CHANGED = 2;
76 
77     /** Event for SIM refresh. */
78     private static final int EVENT_SIM_REFRESH = 3;
79 
80     private final Phone mPhone;
81     private final String mLogTag;
82     private final LocalLog mLocalLog = new LocalLog(128);
83 
84     /** Data network controller. */
85     @NonNull
86     private final DataNetworkController mDataNetworkController;
87 
88     /** Data config manager. */
89     @NonNull
90     private final DataConfigManager mDataConfigManager;
91 
92     /** Cellular data service. */
93     @NonNull
94     private final DataServiceManager mWwanDataServiceManager;
95 
96     /**
97      * All data profiles for the current carrier. Note only data profiles loaded from the APN
98      * database will be stored here. The on-demand data profiles (generated dynamically, for
99      * example, enterprise data profiles with differentiator) are not stored here.
100      */
101     @NonNull
102     private final List<DataProfile> mAllDataProfiles = new ArrayList<>();
103 
104     /** The data profile used for initial attach. */
105     @Nullable
106     private DataProfile mInitialAttachDataProfile = null;
107 
108     /** The preferred data profile used for internet. */
109     @Nullable
110     private DataProfile mPreferredDataProfile = null;
111 
112     /** The last data profile that's successful for internet connection by subscription id. */
113     @NonNull
114     private final LruCache<Integer, DataProfile> mLastInternetDataProfiles = new LruCache<>(256);
115 
116     /** Preferred data profile set id. */
117     private int mPreferredDataProfileSetId = Telephony.Carriers.NO_APN_SET_ID;
118 
119     /** Data profile manager callbacks. */
120     @NonNull
121     private final Set<DataProfileManagerCallback> mDataProfileManagerCallbacks = new ArraySet<>();
122 
123     /** SIM state. */
124     @SimState
125     private int mSimState = TelephonyManager.SIM_STATE_UNKNOWN;
126 
127     /** Feature flags controlling which feature is enabled. */
128     @NonNull
129     private final FeatureFlags mFeatureFlags;
130 
131     /**
132      * Data profile manager callback. This should be only used by {@link DataNetworkController}.
133      */
134     public abstract static class DataProfileManagerCallback extends DataCallback {
135         /**
136          * Constructor
137          *
138          * @param executor The executor of the callback.
139          */
DataProfileManagerCallback(@onNull @allbackExecutor Executor executor)140         public DataProfileManagerCallback(@NonNull @CallbackExecutor Executor executor) {
141             super(executor);
142         }
143 
144         /**
145          * Called when data profiles changed.
146          */
onDataProfilesChanged()147         public abstract void onDataProfilesChanged();
148     }
149 
150     /**
151      * Constructor
152      *
153      * @param phone The phone instance.
154      * @param dataNetworkController Data network controller.
155      * @param dataServiceManager WWAN data service manager.
156      * @param looper The looper to be used by the handler. Currently the handler thread is the
157      * phone process's main thread.
158      * @param featureFlags Feature flags controlling which feature is enabled.
159      * @param callback Data profile manager callback.
160      */
DataProfileManager(@onNull Phone phone, @NonNull DataNetworkController dataNetworkController, @NonNull DataServiceManager dataServiceManager, @NonNull Looper looper, @NonNull FeatureFlags featureFlags, @NonNull DataProfileManagerCallback callback)161     public DataProfileManager(@NonNull Phone phone,
162             @NonNull DataNetworkController dataNetworkController,
163             @NonNull DataServiceManager dataServiceManager, @NonNull Looper looper,
164             @NonNull FeatureFlags featureFlags,
165             @NonNull DataProfileManagerCallback callback) {
166         super(looper);
167         mPhone = phone;
168         mLogTag = "DPM-" + mPhone.getPhoneId();
169         mFeatureFlags = featureFlags;
170         mDataNetworkController = dataNetworkController;
171         mWwanDataServiceManager = dataServiceManager;
172         mDataConfigManager = dataNetworkController.getDataConfigManager();
173         mDataProfileManagerCallbacks.add(callback);
174         registerAllEvents();
175     }
176 
177     /**
178      * Register for all events that data network controller is interested.
179      */
registerAllEvents()180     private void registerAllEvents() {
181         mDataNetworkController.registerDataNetworkControllerCallback(
182                 new DataNetworkControllerCallback(this::post) {
183                     @Override
184                     public void onConnectedInternetDataNetworksChanged(
185                             @NonNull Set<DataNetwork> internetNetworks) {
186                         if (internetNetworks.isEmpty()) return;
187                         DataProfileManager.this.onInternetDataNetworkConnected(internetNetworks);
188                     }
189 
190                     @Override
191                     public void onSimStateChanged(@SimState int simState) {
192                         DataProfileManager.this.mSimState = simState;
193                     }
194                 });
195         mDataConfigManager.registerCallback(new DataConfigManagerCallback(this::post) {
196             @Override
197             public void onCarrierConfigChanged() {
198                 DataProfileManager.this.onCarrierConfigUpdated();
199             }
200         });
201         mPhone.getContext().getContentResolver().registerContentObserver(
202                 Telephony.Carriers.CONTENT_URI, true, new ContentObserver(this) {
203                     @Override
204                     public void onChange(boolean selfChange) {
205                         super.onChange(selfChange);
206                         sendEmptyMessage(EVENT_APN_DATABASE_CHANGED);
207                     }
208                 });
209         mPhone.mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null);
210     }
211 
212     @Override
handleMessage(Message msg)213     public void handleMessage(Message msg) {
214         switch (msg.what) {
215             case EVENT_SIM_REFRESH:
216                 log("Update data profiles due to SIM refresh.");
217                 updateDataProfiles(!mDataConfigManager.allowClearInitialAttachDataProfile()
218                         /*force update IA*/);
219                 break;
220             case EVENT_APN_DATABASE_CHANGED:
221                 log("Update data profiles due to APN db updated.");
222                 updateDataProfiles(false/*force update IA*/);
223                 break;
224             default:
225                 loge("Unexpected event " + msg);
226                 break;
227         }
228     }
229 
230     /**
231      * Called when carrier config was updated.
232      */
onCarrierConfigUpdated()233     private void onCarrierConfigUpdated() {
234         log("Update data profiles due to carrier config updated.");
235         updateDataProfiles(!mDataConfigManager.allowClearInitialAttachDataProfile()
236                 /*force update IA*/);
237     }
238 
239     /**
240      * Check if there are any Enterprise APN configured by DPC and return a data profile
241      * with the same.
242      * @return data profile with enterprise ApnSetting if available, else null
243      */
getEnterpriseDataProfile()244     @Nullable private DataProfile getEnterpriseDataProfile() {
245         Cursor cursor = mPhone.getContext().getContentResolver().query(
246                 Telephony.Carriers.DPC_URI, null, null, null, null);
247         if (cursor == null) {
248             loge("Cannot access APN database through telephony provider.");
249             return null;
250         }
251 
252         DataProfile dataProfile = null;
253         while (cursor.moveToNext()) {
254             ApnSetting apn = ApnSetting.makeApnSetting(cursor);
255             if (apn != null) {
256                 dataProfile = new DataProfile.Builder()
257                         .setApnSetting(apn)
258                         .setTrafficDescriptor(new TrafficDescriptor(apn.getApnName(), null))
259                         .setPreferred(false)
260                         .build();
261                 if (dataProfile.canSatisfy(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)) {
262                     break;
263                 }
264             }
265         }
266         cursor.close();
267         return dataProfile;
268     }
269 
270     /**
271      * Update all data profiles, including preferred data profile, and initial attach data profile.
272      * Also send those profiles down to the modem if needed.
273      *
274      * @param forceUpdateIa If {@code true}, we should always send initial attach data profile again
275      *                     to modem.
276      */
updateDataProfiles(boolean forceUpdateIa)277     private void updateDataProfiles(boolean forceUpdateIa) {
278         List<DataProfile> profiles = new ArrayList<>();
279         if (mDataConfigManager.isConfigCarrierSpecific()) {
280             Cursor cursor = mPhone.getContext().getContentResolver().query(
281                     Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, "filtered/subId/"
282                             + mPhone.getSubId()), null, null, null, Telephony.Carriers._ID);
283             if (cursor == null) {
284                 loge("Cannot access APN database through telephony provider.");
285                 return;
286             }
287             boolean isInternetSupported = false;
288             while (cursor.moveToNext()) {
289                 ApnSetting apn = ApnSetting.makeApnSetting(cursor);
290                 if (apn != null) {
291                     DataProfile dataProfile = new DataProfile.Builder()
292                             .setApnSetting(apn)
293                             .setTrafficDescriptor(new TrafficDescriptor(apn.getApnName(), null))
294                             .setPreferred(false)
295                             .build();
296                     profiles.add(dataProfile);
297                     log("Added " + dataProfile);
298 
299                     isInternetSupported |= apn.canHandleType(ApnSetting.TYPE_DEFAULT);
300                     if (mDataConfigManager.isApnConfigAnomalyReportEnabled()
301                             && apn.getEditedStatus() == Telephony.Carriers.UNEDITED) {
302                         checkApnSetting(apn);
303                     }
304                 }
305             }
306             cursor.close();
307 
308             if (!isInternetSupported
309                     && !profiles.isEmpty() // APN database has been read successfully
310                     && mDataConfigManager.isApnConfigAnomalyReportEnabled()) {
311                 reportAnomaly("Carrier doesn't support internet.",
312                         "9af73e18-b523-4dc5-adab-363eb6613305");
313             }
314         }
315 
316         DataProfile dataProfile;
317 
318         if (mSimState == TelephonyManager.SIM_STATE_LOADED) {
319             // Check if any of the profile already supports IMS, if not, add the default one.
320             dataProfile = profiles.stream()
321                     .filter(dp -> dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS))
322                     .findFirst()
323                     .orElse(null);
324             if (dataProfile == null) {
325                 profiles.add(new DataProfile.Builder()
326                         .setApnSetting(buildDefaultApnSetting("DEFAULT IMS", "ims",
327                                 ApnSetting.TYPE_IMS))
328                         .setTrafficDescriptor(new TrafficDescriptor("ims", null))
329                         .build());
330                 log("Added default IMS data profile.");
331             }
332         }
333 
334         // Check if any of the profile already supports ENTERPRISE, if not, check if DPC has
335         // configured one and retrieve the same.
336         dataProfile = profiles.stream()
337                 .filter(dp -> dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE))
338                 .findFirst()
339                 .orElse(null);
340         if (dataProfile == null) {
341             dataProfile = getEnterpriseDataProfile();
342             if (dataProfile != null) {
343                 profiles.add(dataProfile);
344                 log("Added enterprise profile " + dataProfile);
345             }
346         }
347 
348         // Check if any of the profile already supports EIMS, if not, add the default one.
349         dataProfile = profiles.stream()
350                 .filter(dp -> dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_EIMS))
351                 .findFirst()
352                 .orElse(null);
353         if (dataProfile == null) {
354             profiles.add(new DataProfile.Builder()
355                     .setApnSetting(buildDefaultApnSetting("DEFAULT EIMS", "sos",
356                             ApnSetting.TYPE_EMERGENCY))
357                     .setTrafficDescriptor(new TrafficDescriptor("sos", null))
358                     .build());
359             log("Added default EIMS data profile.");
360         }
361 
362         dedupeDataProfiles(profiles);
363 
364         if (mDataConfigManager.isApnConfigAnomalyReportEnabled()) {
365             checkDataProfiles(profiles);
366         }
367 
368         log("Found " + profiles.size() + " data profiles. profiles = " + profiles);
369 
370         boolean profilesChanged = false;
371         if (mAllDataProfiles.size() != profiles.size() || !mAllDataProfiles.containsAll(profiles)) {
372             log("Data profiles changed.");
373             mAllDataProfiles.clear();
374             mAllDataProfiles.addAll(profiles);
375             profilesChanged = true;
376         }
377 
378         // Reload the latest preferred data profile from either database or config.
379         profilesChanged |= updatePreferredDataProfile();
380 
381         int setId = getPreferredDataProfileSetId();
382         if (setId != mPreferredDataProfileSetId) {
383             logl("Changed preferred data profile set id to " + setId);
384             mPreferredDataProfileSetId = setId;
385             profilesChanged = true;
386         }
387 
388         updateDataProfilesAtModem();
389         updateInitialAttachDataProfileAtModem(forceUpdateIa);
390 
391         if (profilesChanged) {
392             mDataProfileManagerCallbacks.forEach(callback -> callback.invokeFromExecutor(
393                     callback::onDataProfilesChanged));
394         }
395     }
396 
397     /**
398      * @return The preferred data profile set id.
399      */
getPreferredDataProfileSetId()400     private int getPreferredDataProfileSetId() {
401         // Query the preferred APN set id. The set id is automatically set when we set by
402         // TelephonyProvider when setting preferred APN in setPreferredDataProfile().
403         Cursor cursor = mPhone.getContext().getContentResolver()
404                 .query(Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_SET_URI,
405                         String.valueOf(mPhone.getSubId())),
406                         new String[] {Telephony.Carriers.APN_SET_ID}, null, null, null);
407         // Returns all APNs for the current carrier which have an apn_set_id
408         // equal to the preferred APN (if no preferred APN, or if the preferred APN has no set id,
409         // the query will return null)
410         if (cursor == null) {
411             log("getPreferredDataProfileSetId: cursor is null");
412             return Telephony.Carriers.NO_APN_SET_ID;
413         }
414 
415         int setId;
416         if (cursor.getCount() < 1) {
417             loge("getPreferredDataProfileSetId: no APNs found");
418             setId = Telephony.Carriers.NO_APN_SET_ID;
419         } else {
420             cursor.moveToFirst();
421             setId = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID));
422         }
423 
424         cursor.close();
425         return setId;
426     }
427 
428     /**
429      * Called when new internet data connect.
430      *
431      * @param internetNetworks The connected internet data networks.
432      */
onInternetDataNetworkConnected(@onNull Set<DataNetwork> internetNetworks)433     private void onInternetDataNetworkConnected(@NonNull Set<DataNetwork> internetNetworks) {
434         DataProfile defaultProfile = null;
435         if (mFeatureFlags.refinePreferredDataProfileSelection()) {
436             // Most of the cases there should be only one.
437             // but in case there are multiple, find the default internet network, and choose the
438             // one which has longest life cycle.
439             defaultProfile = internetNetworks.stream()
440                     .filter(network -> mPreferredDataProfile == null
441                             // Find the one most resembles the current preferred profile,
442                             // avoiding e.g. DUN default network.
443                             || canPreferredDataProfileSatisfy(
444                             network.getAttachedNetworkRequestList()))
445                     .map(DataNetwork::getDataProfile)
446                     .min(Comparator.comparingLong(DataProfile::getLastSetupTimestamp))
447                     .orElse(null);
448         } else {
449             if (internetNetworks.size() == 1) {
450                 // Most of the cases there should be only one.
451                 defaultProfile = internetNetworks.stream().findFirst().get().getDataProfile();
452             } else if (internetNetworks.size() > 1) {
453                 // but in case there are multiple, find the default internet network, and choose the
454                 // one which has longest life cycle.
455                 defaultProfile = internetNetworks.stream()
456                         .filter(network -> mPreferredDataProfile == null
457                                 || canPreferredDataProfileSatisfy(
458                                 network.getAttachedNetworkRequestList()))
459                         .map(DataNetwork::getDataProfile)
460                         .min(Comparator.comparingLong(DataProfile::getLastSetupTimestamp))
461                         .orElse(null);
462             }
463         }
464 
465         // Update a working internet data profile by subid as a future candidate for preferred
466         // data profile after APNs are reset to default
467         if (defaultProfile != null) {
468             mLastInternetDataProfiles.put(mPhone.getSubId(), defaultProfile);
469         }
470 
471         // If the live default internet network is not using the preferred data profile, since
472         // brought up a network means it passed sophisticated checks, update the preferred data
473         // profile so that this network won't be torn down in future network evaluations.
474         if (defaultProfile == null || defaultProfile.equals(mPreferredDataProfile)) return;
475         logv("onInternetDataNetworkConnected: defaultProfile=" + defaultProfile
476                 + " previous preferredDataProfile=" + mPreferredDataProfile
477                 + " internetNetworks=" + internetNetworks);
478         // Save the preferred data profile into database.
479         setPreferredDataProfile(defaultProfile);
480         updateDataProfiles(false/*force update IA*/);
481     }
482 
483     /**
484      * Get the preferred data profile for internet data.
485      *
486      * @return The preferred data profile.
487      */
488     @Nullable
getPreferredDataProfileFromDb()489     private DataProfile getPreferredDataProfileFromDb() {
490         Cursor cursor = mPhone.getContext().getContentResolver().query(
491                 Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_URI,
492                         String.valueOf(mPhone.getSubId())), null, null, null,
493                 Telephony.Carriers.DEFAULT_SORT_ORDER);
494         DataProfile dataProfile = null;
495         if (cursor != null) {
496             if (cursor.getCount() > 0) {
497                 cursor.moveToFirst();
498                 int apnId = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
499                 dataProfile = mAllDataProfiles.stream()
500                         .filter(dp -> dp.getApnSetting() != null
501                                 && dp.getApnSetting().getId() == apnId)
502                         .findFirst()
503                         .orElse(null);
504             }
505             cursor.close();
506         }
507         log("getPreferredDataProfileFromDb: " + dataProfile);
508         return dataProfile;
509     }
510 
511     /**
512      * @return The preferred data profile from carrier config.
513      */
514     @Nullable
getPreferredDataProfileFromConfig()515     private DataProfile getPreferredDataProfileFromConfig() {
516         // Check if there is configured default preferred data profile.
517         String defaultPreferredApn = mDataConfigManager.getDefaultPreferredApn();
518         if (!TextUtils.isEmpty(defaultPreferredApn)) {
519             return mAllDataProfiles.stream()
520                     .filter(dp -> dp.getApnSetting() != null && defaultPreferredApn.equals(
521                                     dp.getApnSetting().getApnName()))
522                     .findFirst()
523                     .orElse(null);
524         }
525         return null;
526     }
527 
528     /**
529      * Save the preferred data profile into the database.
530      *
531      * @param dataProfile The preferred data profile used for internet data. {@code null} to clear
532      * the preferred data profile from database.
533      */
setPreferredDataProfile(@ullable DataProfile dataProfile)534     private void setPreferredDataProfile(@Nullable DataProfile dataProfile) {
535         logl("setPreferredDataProfile: " + dataProfile);
536 
537         String subId = Long.toString(mPhone.getSubId());
538         Uri uri = Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_URI, subId);
539         ContentResolver resolver = mPhone.getContext().getContentResolver();
540         resolver.delete(uri, null, null);
541 
542         if (dataProfile != null && dataProfile.getApnSetting() != null) {
543             ContentValues values = new ContentValues();
544             // Fill only the id here. TelephonyProvider will pull the rest of key fields and write
545             // into the database.
546             values.put(Telephony.Carriers.APN_ID, dataProfile.getApnSetting().getId());
547             resolver.insert(uri, values);
548         }
549     }
550 
551     /**
552      * Reload the latest preferred data profile from either database or the config. This is to
553      * make sure the cached {@link #mPreferredDataProfile} is in-sync.
554      *
555      * @return {@code true} if preferred data profile changed.
556      */
updatePreferredDataProfile()557     private boolean updatePreferredDataProfile() {
558         DataProfile preferredDataProfile;
559         int subId = mPhone.getSubId();
560         if (SubscriptionManager.isValidSubscriptionId(subId)) {
561             preferredDataProfile = getPreferredDataProfileFromDb();
562             if (preferredDataProfile == null) {
563                 preferredDataProfile = getPreferredDataProfileFromConfig();
564                 if (preferredDataProfile != null) {
565                     // Save the carrier specified preferred data profile into database
566                     setPreferredDataProfile(preferredDataProfile);
567                 } else {
568                     preferredDataProfile = mAllDataProfiles.stream()
569                             .filter(dp -> areDataProfilesSharingApn(dp,
570                                     mLastInternetDataProfiles.get(subId)))
571                             .findFirst()
572                             .orElse(null);
573                     if (preferredDataProfile != null) {
574                         log("updatePreferredDataProfile: preferredDB is empty and no carrier "
575                                 + "default configured, setting preferred to be prev internet DP.");
576                         setPreferredDataProfile(preferredDataProfile);
577                     }
578                 }
579             }
580         } else {
581             preferredDataProfile = null;
582         }
583 
584         for (DataProfile dataProfile : mAllDataProfiles) {
585             dataProfile.setPreferred(dataProfile.equals(preferredDataProfile));
586         }
587 
588         if (!Objects.equals(mPreferredDataProfile, preferredDataProfile)) {
589             mPreferredDataProfile = preferredDataProfile;
590 
591             logl("Changed preferred data profile to " + mPreferredDataProfile);
592             return true;
593         }
594         return false;
595     }
596 
597     /**
598      * Update the data profile used for initial attach.
599      * <p>
600      * Note that starting from Android 13 only APNs that supports "IA" type will be used for
601      * initial attach. Please update APN configuration file if needed.
602      * <p>
603      * Some carriers might explicitly require that using "user-added" APN for initial
604      * attach. In this case, exception can be configured through
605      * {@link CarrierConfigManager#KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY}.
606      *
607      * @param forceUpdateIa If {@code true}, we should always send initial attach data profile again
608      *                     to modem.
609      */
updateInitialAttachDataProfileAtModem(boolean forceUpdateIa)610     private void updateInitialAttachDataProfileAtModem(boolean forceUpdateIa) {
611         DataProfile initialAttachDataProfile = null;
612 
613         // Sort the data profiles so the preferred data profile is at the beginning.
614         List<DataProfile> allDataProfiles = mAllDataProfiles.stream()
615                 .sorted(Comparator.comparing((DataProfile dp) -> !dp.equals(mPreferredDataProfile)))
616                 .toList();
617         // Search in the order. "IA" type should be the first from getAllowedInitialAttachApnTypes.
618         for (int apnType : mDataConfigManager.getAllowedInitialAttachApnTypes()) {
619             initialAttachDataProfile = allDataProfiles.stream()
620                     .filter(dp -> dp.canSatisfy(DataUtils.apnTypeToNetworkCapability(apnType)))
621                     .findFirst()
622                     .orElse(null);
623             if (initialAttachDataProfile != null) break;
624         }
625 
626         if (forceUpdateIa || !Objects.equals(mInitialAttachDataProfile, initialAttachDataProfile)) {
627             mInitialAttachDataProfile = initialAttachDataProfile;
628             logl("Initial attach data profile updated as " + mInitialAttachDataProfile
629                     + " or forceUpdateIa= " + forceUpdateIa);
630             if (mInitialAttachDataProfile != null || mDataConfigManager
631                     .allowClearInitialAttachDataProfile()) {
632                 mWwanDataServiceManager.setInitialAttachApn(mInitialAttachDataProfile,
633                         mPhone.getServiceState().getDataRoamingFromRegistration(), null);
634             }
635         }
636     }
637 
638     /**
639      * Update the data profiles at modem.
640      */
updateDataProfilesAtModem()641     private void updateDataProfilesAtModem() {
642         log("updateDataProfilesAtModem: set " + mAllDataProfiles.size() + " data profiles.");
643         mWwanDataServiceManager.setDataProfile(mAllDataProfiles,
644                 mPhone.getServiceState().getDataRoamingFromRegistration(), null);
645     }
646 
647     /**
648      * Create default apn settings for the apn type like emergency, and ims
649      *
650      * @param entry Entry name
651      * @param apn APN name
652      * @param apnTypeBitmask APN type
653      * @return The APN setting
654      */
655     @NonNull
buildDefaultApnSetting(@onNull String entry, @NonNull String apn, @Annotation.ApnType int apnTypeBitmask)656     private ApnSetting buildDefaultApnSetting(@NonNull String entry,
657             @NonNull String apn, @Annotation.ApnType int apnTypeBitmask) {
658         return new ApnSetting.Builder()
659                 .setEntryName(entry)
660                 .setProtocol(ApnSetting.PROTOCOL_IPV4V6)
661                 .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6)
662                 .setApnName(apn)
663                 .setApnTypeBitmask(apnTypeBitmask)
664                 .setCarrierEnabled(true)
665                 .setApnSetId(Telephony.Carriers.MATCH_ALL_APN_SET_ID)
666                 .build();
667     }
668 
669     /**
670      * Get the data profile that can satisfy the network request.
671      *
672      * @param networkRequest The network request.
673      * @param networkType The current data network type.
674      * @param isNtn {@code true} if the device is currently attached to non-terrestrial network.
675      * @param ignorePermanentFailure {@code true} to ignore {@link ApnSetting#getPermanentFailed()}.
676      * This should be set to true for condition-based retry/setup.
677      * @return The data profile. {@code null} if can't find any satisfiable data profile.
678      */
679     @Nullable
getDataProfileForNetworkRequest( @onNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType, boolean isNtn, boolean isEsimBootstrapProvisioning, boolean ignorePermanentFailure)680     public DataProfile getDataProfileForNetworkRequest(
681             @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType,
682             boolean isNtn, boolean isEsimBootstrapProvisioning, boolean ignorePermanentFailure) {
683         ApnSetting apnSetting = null;
684         if (networkRequest.hasAttribute(TelephonyNetworkRequest
685                 .CAPABILITY_ATTRIBUTE_APN_SETTING)) {
686             apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType, isNtn,
687                     isEsimBootstrapProvisioning, ignorePermanentFailure);
688         }
689 
690         TrafficDescriptor.Builder trafficDescriptorBuilder = new TrafficDescriptor.Builder();
691         if (networkRequest.hasAttribute(TelephonyNetworkRequest
692                 .CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_DNN)) {
693             if (apnSetting != null) {
694                 trafficDescriptorBuilder.setDataNetworkName(apnSetting.getApnName());
695             }
696         }
697 
698         if (networkRequest.hasAttribute(
699                 TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_TRAFFIC_DESCRIPTOR_OS_APP_ID)) {
700             TrafficDescriptor.OsAppId osAppId = networkRequest.getOsAppId();
701             if (osAppId != null) {
702                 trafficDescriptorBuilder.setOsAppId(osAppId.getBytes());
703             }
704         }
705 
706         TrafficDescriptor trafficDescriptor;
707         try {
708             trafficDescriptor = trafficDescriptorBuilder.build();
709         } catch (IllegalArgumentException e) {
710             // We reach here when both ApnSetting and trafficDescriptor are null.
711             log("Unable to find a data profile for " + networkRequest);
712             return null;
713         }
714 
715         // Instead of building the data profile from APN setting and traffic descriptor on-the-fly,
716         // find the existing one from mAllDataProfiles so the last-setup timestamp can be retained.
717         // Only create a new one when it can't be found.
718         for (DataProfile dataProfile : mAllDataProfiles) {
719             if (Objects.equals(apnSetting, dataProfile.getApnSetting())
720                     && trafficDescriptor.equals(dataProfile.getTrafficDescriptor())) {
721                 return dataProfile;
722             }
723         }
724 
725         // When reaching here, it means that we have a valid non-null traffic descriptor, but
726         // could not find it in mAllDataProfiles. This could happen on the traffic descriptor
727         // capable capabilities like ENTERPRISE.
728         DataProfile.Builder profileBuilder = new DataProfile.Builder();
729         if (apnSetting != null) {
730             profileBuilder.setApnSetting(apnSetting);
731         }
732 
733         // trafficDescriptor is always non-null when we reach here.
734         profileBuilder.setTrafficDescriptor(trafficDescriptor);
735 
736         DataProfile dataProfile = profileBuilder.build();
737         log("Created data profile " + dataProfile + " for " + networkRequest);
738         return dataProfile;
739     }
740 
741     /**
742      * Get the APN setting for the network request.
743      *
744      * @param networkRequest The network request.
745      * @param networkType The current data network type.
746      * @param isNtn {@code true} if the device is currently attached to non-terrestrial network.
747      * @param ignorePermanentFailure {@code true} to ignore {@link ApnSetting#getPermanentFailed()}.
748      * This should be set to true for condition-based retry/setup.
749      * @return The APN setting. {@code null} if can't find any satisfiable data profile.
750      */
751     @Nullable
getApnSettingForNetworkRequest( @onNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType, boolean isNtn, boolean isEsimBootStrapProvisioning, boolean ignorePermanentFailure)752     private ApnSetting getApnSettingForNetworkRequest(
753             @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType,
754             boolean isNtn, boolean isEsimBootStrapProvisioning, boolean ignorePermanentFailure) {
755         if (!networkRequest.hasAttribute(
756                 TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_APN_SETTING)) {
757             loge("Network request does not have APN setting attribute.");
758             return null;
759         }
760 
761         // if esim bootstrap provisioning in progress, do not apply preferred data profile
762         if (!isEsimBootStrapProvisioning) {
763             if (mFeatureFlags.carrierEnabledSatelliteFlag()) {
764                 // If the preferred data profile can be used, always use it if it can satisfy the
765                 // network request with current network type (even though it's been marked as
766                 // permanent failed.)
767                 if (mPreferredDataProfile != null
768                         && networkRequest.canBeSatisfiedBy(mPreferredDataProfile)
769                         && mPreferredDataProfile.getApnSetting() != null
770                         && mPreferredDataProfile.getApnSetting().canSupportNetworkType(networkType)
771                         && ((isNtn && mPreferredDataProfile.getApnSetting().isForInfrastructure(
772                         ApnSetting.INFRASTRUCTURE_SATELLITE))
773                         || (!isNtn && mPreferredDataProfile.getApnSetting().isForInfrastructure(
774                         ApnSetting.INFRASTRUCTURE_CELLULAR)))) {
775                     if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting()
776                             .getPermanentFailed()) {
777                         return mPreferredDataProfile.getApnSetting();
778                     }
779                     log("The preferred data profile is permanently failed. Only condition based "
780                             + "retry can happen.");
781                     return null;
782                 }
783             } else {
784                 // If the preferred data profile can be used, always use it if it can satisfy the
785                 // network request with current network type (even though it's been marked as
786                 // permanent failed.)
787                 if (mPreferredDataProfile != null
788                         && networkRequest.canBeSatisfiedBy(mPreferredDataProfile)
789                         && mPreferredDataProfile.getApnSetting() != null
790                         && mPreferredDataProfile.getApnSetting()
791                         .canSupportNetworkType(networkType)) {
792                     if (ignorePermanentFailure || !mPreferredDataProfile.getApnSetting()
793                             .getPermanentFailed()) {
794                         return mPreferredDataProfile.getApnSetting();
795                     }
796                     log("The preferred data profile is permanently failed. Only condition based "
797                             + "retry can happen.");
798                     return null;
799                 }
800             }
801         }
802 
803         // Filter out the data profile that can't satisfy the request.
804         // Preferred data profile should be returned in the top of the list.
805         List<DataProfile> dataProfiles = mAllDataProfiles.stream()
806                 .filter(networkRequest::canBeSatisfiedBy)
807                 // The longest time hasn't used data profile will be in the front so all the data
808                 // profiles can be tried.
809                 .sorted(Comparator.comparing(DataProfile::getLastSetupTimestamp))
810                 .collect(Collectors.toList());
811         for (DataProfile dataProfile : dataProfiles) {
812             logv("Satisfied profile: " + dataProfile + ", last setup="
813                     + DataUtils.elapsedTimeToString(dataProfile.getLastSetupTimestamp()));
814         }
815         if (dataProfiles.isEmpty()) {
816             log("Can't find any data profile that can satisfy " + networkRequest);
817             return null;
818         }
819 
820         // Check if the remaining data profiles can used in current data network type.
821         dataProfiles = dataProfiles.stream()
822                 .filter((dp) -> {
823                     if (dp.getApnSetting() == null) return false;
824                     if (!dp.getApnSetting().canSupportNetworkType(networkType)) return false;
825                     if (isEsimBootStrapProvisioning
826                             != dp.getApnSetting().isEsimBootstrapProvisioning()) return false;
827                     if (mFeatureFlags.carrierEnabledSatelliteFlag()) {
828                         if (isNtn && !dp.getApnSetting().isForInfrastructure(
829                                 ApnSetting.INFRASTRUCTURE_SATELLITE)) {
830                             return false;
831                         }
832                         return isNtn || dp.getApnSetting().isForInfrastructure(
833                                 ApnSetting.INFRASTRUCTURE_CELLULAR);
834                     }
835 
836                     return true;
837                 })
838                 .collect(Collectors.toList());
839         if (dataProfiles.isEmpty()) {
840             String ntnReason = "";
841             if (mFeatureFlags.carrierEnabledSatelliteFlag()) {
842                 ntnReason = " and infrastructure for "
843                         + NetworkRegistrationInfo.isNonTerrestrialNetworkToString(isNtn);
844             }
845             log("Can't find any data profile for network type "
846                     + TelephonyManager.getNetworkTypeName(networkType) + ntnReason);
847             return null;
848         }
849 
850         // Check if preferred data profile set id matches.
851         dataProfiles = dataProfiles.stream()
852                 .filter(dp -> dp.getApnSetting() != null
853                         && (dp.getApnSetting().getApnSetId()
854                         == Telephony.Carriers.MATCH_ALL_APN_SET_ID
855                         || dp.getApnSetting().getApnSetId() == mPreferredDataProfileSetId))
856                 .collect(Collectors.toList());
857         if (dataProfiles.isEmpty()) {
858             log("Can't find any data profile has APN set id matched. mPreferredDataProfileSetId="
859                     + mPreferredDataProfileSetId);
860             return null;
861         }
862 
863         // Check if data profiles are permanently failed.
864         dataProfiles = dataProfiles.stream()
865                 .filter(dp -> ignorePermanentFailure || (dp.getApnSetting() != null
866                         && !dp.getApnSetting().getPermanentFailed()))
867                 .collect(Collectors.toList());
868         if (dataProfiles.isEmpty()) {
869             log("The suitable data profiles are all in permanent failed state.");
870             return null;
871         }
872 
873         if (isEsimBootStrapProvisioning) {
874             log("Found esim bootstrap provisioning data profile for network request: "
875                     + dataProfiles.get(0).getApnSetting());
876         }
877         return dataProfiles.get(0).getApnSetting();
878     }
879 
880     /**
881      * Check if the data profile is essentially the preferred data profile. The non-essential
882      * elements include e.g.APN Id.
883      *
884      * @param dataProfile The data profile to check.
885      * @return {@code true} if the data profile is essentially the preferred data profile.
886      */
isDataProfilePreferred(@onNull DataProfile dataProfile)887     public boolean isDataProfilePreferred(@NonNull DataProfile dataProfile) {
888         return areDataProfilesSharingApn(dataProfile, mPreferredDataProfile);
889     }
890 
891     /**
892      * @param networkRequests The required network requests
893      * @return {@code true} if we currently have a preferred data profile that's capable of
894      * satisfying the required network requests; {@code false} if we have no preferred, or the
895      * preferred cannot satisfy the required requests.
896      */
canPreferredDataProfileSatisfy( @onNull DataNetworkController.NetworkRequestList networkRequests)897     public boolean canPreferredDataProfileSatisfy(
898             @NonNull DataNetworkController.NetworkRequestList networkRequests) {
899         return mPreferredDataProfile != null && networkRequests.stream()
900                 .allMatch(request -> request.canBeSatisfiedBy(mPreferredDataProfile));
901     }
902 
903     /**
904      * Check if there is tethering data profile for certain network type.
905      *
906      * @param networkType The network type
907      * @return {@code true} if tethering data profile is found. {@code false} if no specific profile
908      * should used for tethering. In this case, tethering service will use internet network for
909      * tethering.
910      */
isTetheringDataProfileExisting(@etworkType int networkType)911     public boolean isTetheringDataProfileExisting(@NetworkType int networkType) {
912         if (mDataConfigManager.isTetheringProfileDisabledForRoaming()
913                 && mPhone.getServiceState().getDataRoaming()) {
914             // Use internet network for tethering.
915             return false;
916         }
917         TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(
918                 new NetworkRequest.Builder()
919                         .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN)
920                         .build(), mPhone, mFeatureFlags);
921         return getDataProfileForNetworkRequest(networkRequest, networkType,
922                 mPhone.getServiceState().isUsingNonTerrestrialNetwork(),
923                 mDataNetworkController.isEsimBootStrapProvisioningActivated(),
924                 true) != null;
925     }
926 
927     /**
928      * Dedupe the similar data profiles.
929      */
dedupeDataProfiles(@onNull List<DataProfile> dataProfiles)930     private void dedupeDataProfiles(@NonNull List<DataProfile> dataProfiles) {
931         int i = 0;
932         while (i < dataProfiles.size() - 1) {
933             DataProfile first = dataProfiles.get(i);
934             int j = i + 1;
935             while (j < dataProfiles.size()) {
936                 DataProfile second = dataProfiles.get(j);
937                 DataProfile merged = mergeDataProfiles(first, second);
938                 if (merged != null) {
939                     log("Created a merged profile " + merged + " from " + first + " and "
940                             + second);
941                     loge("Merging data profiles will not be supported anymore. Please "
942                             + "directly configure the merged profile " + merged + " in the APN "
943                             + "config.");
944                     dataProfiles.set(i, merged);
945                     dataProfiles.remove(j);
946                 } else {
947                     j++;
948                 }
949             }
950             i++;
951         }
952     }
953 
954     /**
955      * Trigger anomaly report if APN Setting contains invalid info.
956      *
957      * @param setting The Apn setting to be checked.
958      */
checkApnSetting(@onNull ApnSetting setting)959     private void checkApnSetting(@NonNull ApnSetting setting) {
960         if (setting.canHandleType(ApnSetting.TYPE_MMS)
961                 && setting.getEditedStatus() == Telephony.Carriers.UNEDITED) {
962             if (setting.getMmsc() == null) {
963                 reportAnomaly("MMS is supported but no MMSC configured " + setting,
964                         "9af73e18-b523-4dc5-adab-19d86c6a3685");
965             } else if (!setting.getMmsc().toString().matches("^https?:\\/\\/.+")) {
966                 reportAnomaly("Apn config mmsc should start with http but is "
967                                 + setting.getMmsc(),
968                         "9af73e18-b523-4dc5-adab-ec754d959d4d");
969             }
970             if (!TextUtils.isEmpty(setting.getMmsProxyAddressAsString())
971                     && setting.getMmsProxyAddressAsString().matches("^https?:\\/\\/.+")) {
972                 reportAnomaly("Apn config mmsc_proxy should NOT start with http but is "
973                                 + setting.getMmsc(), "9af73e18-b523-4dc5-adab-ec754d959d4d");
974             }
975         }
976     }
977 
978     /**
979      * Trigger anomaly report if any two Apn Settings share the same APN name while having
980      * overlapped network types.
981      *
982      * @param profiles The list of data profiles to be checked.
983      */
checkDataProfiles(List<DataProfile> profiles)984     private void checkDataProfiles(List<DataProfile> profiles) {
985         for (int i = 0; i < profiles.size(); i++) {
986             ApnSetting a = profiles.get(i).getApnSetting();
987             if (a == null || a.getEditedStatus() != Telephony.Carriers.UNEDITED) continue;
988             if (// Lingering network is not the default and doesn't cover all the regular networks
989                     (int) TelephonyManager.NETWORK_TYPE_BITMASK_UNKNOWN
990                     != a.getLingeringNetworkTypeBitmask()
991                             && (a.getNetworkTypeBitmask() | a.getLingeringNetworkTypeBitmask())
992                     != a.getLingeringNetworkTypeBitmask()) {
993                 reportAnomaly("Apn[" + a.getApnName() + "] network "
994                                 + TelephonyManager.convertNetworkTypeBitmaskToString(
995                                         a.getNetworkTypeBitmask()) + " should be a subset of "
996                                 + "the lingering network "
997                                 + TelephonyManager.convertNetworkTypeBitmaskToString(
998                                 a.getLingeringNetworkTypeBitmask()),
999                         "9af73e18-b523-4dc5-adab-4bb24355d838");
1000             }
1001         }
1002     }
1003 
1004     /**
1005      * Merge two data profiles if possible.
1006      *
1007      * @param dp1 Data profile 1 to be merged.
1008      * @param dp2 Data profile 2 to be merged.
1009      *
1010      * @return The merged data profile. {@code null} if merging is not possible.
1011      */
1012     @Nullable
mergeDataProfiles( @onNull DataProfile dp1, @NonNull DataProfile dp2)1013     private static DataProfile mergeDataProfiles(
1014             @NonNull DataProfile dp1, @NonNull DataProfile dp2) {
1015         Objects.requireNonNull(dp1);
1016         Objects.requireNonNull(dp2);
1017 
1018         // We don't merge data profiles that have different traffic descriptor.
1019         if (!Objects.equals(dp1.getTrafficDescriptor(), dp2.getTrafficDescriptor())) return null;
1020 
1021         // If one of the APN setting is null, we don't merge.
1022         if (dp1.getApnSetting() == null || dp2.getApnSetting() == null) return null;
1023 
1024         // If two APN settings are not similar, we don't merge.
1025         if (!dp1.getApnSetting().similar(dp2.getApnSetting())) return null;
1026 
1027         // Start to merge APN setting 1 and 2.
1028         ApnSetting apn1 = dp1.getApnSetting();
1029         ApnSetting apn2 = dp2.getApnSetting();
1030         ApnSetting.Builder apnBuilder = new ApnSetting.Builder();
1031 
1032         // Special handling id and entry name. We want to keep the default APN as it could be the
1033         // preferred APN.
1034         apnBuilder.setId(apn1.getId());
1035         apnBuilder.setEntryName(apn1.getEntryName());
1036         if (apn2.canHandleType(ApnSetting.TYPE_DEFAULT)
1037                 && !apn1.canHandleType(ApnSetting.TYPE_DEFAULT)) {
1038             apnBuilder.setId(apn2.getId());
1039             apnBuilder.setEntryName(apn2.getEntryName());
1040         }
1041 
1042         // Merge the following fields from apn1 and apn2.
1043         apnBuilder.setProxyAddress(TextUtils.isEmpty(apn2.getProxyAddressAsString())
1044                 ? apn1.getProxyAddressAsString() : apn2.getProxyAddressAsString());
1045         apnBuilder.setProxyPort(apn2.getProxyPort() == -1
1046                 ? apn1.getProxyPort() : apn2.getProxyPort());
1047         apnBuilder.setMmsc(apn2.getMmsc() == null ? apn1.getMmsc() : apn2.getMmsc());
1048         apnBuilder.setMmsProxyAddress(TextUtils.isEmpty(apn2.getMmsProxyAddressAsString())
1049                 ? apn1.getMmsProxyAddressAsString() : apn2.getMmsProxyAddressAsString());
1050         apnBuilder.setMmsProxyPort(apn2.getMmsProxyPort() == -1
1051                 ? apn1.getMmsProxyPort() : apn2.getMmsProxyPort());
1052         apnBuilder.setUser(TextUtils.isEmpty(apn2.getUser()) ? apn1.getUser() : apn2.getUser());
1053         apnBuilder.setPassword(TextUtils.isEmpty(apn2.getPassword())
1054                 ? apn1.getPassword() : apn2.getPassword());
1055         apnBuilder.setAuthType(apn2.getAuthType() == -1
1056                 ? apn1.getAuthType() : apn2.getAuthType());
1057         apnBuilder.setApnTypeBitmask(apn1.getApnTypeBitmask() | apn2.getApnTypeBitmask());
1058         apnBuilder.setMtuV4(apn2.getMtuV4() <= ApnSetting.UNSET_MTU
1059                 ? apn1.getMtuV4() : apn2.getMtuV4());
1060         apnBuilder.setMtuV6(apn2.getMtuV6() <= ApnSetting.UNSET_MTU
1061                 ? apn1.getMtuV6() : apn2.getMtuV6());
1062         // legacy properties that don't matter
1063         apnBuilder.setMvnoType(apn1.getMvnoType());
1064         apnBuilder.setMvnoMatchData(apn1.getMvnoMatchData());
1065 
1066         // The following fields in apn1 and apn2 should be the same, otherwise ApnSetting.similar()
1067         // should fail earlier.
1068         apnBuilder.setApnName(apn1.getApnName());
1069         apnBuilder.setOperatorNumeric(apn1.getOperatorNumeric());
1070         apnBuilder.setProtocol(apn1.getProtocol());
1071         apnBuilder.setRoamingProtocol(apn1.getRoamingProtocol());
1072         apnBuilder.setCarrierEnabled(apn1.isEnabled());
1073         apnBuilder.setNetworkTypeBitmask(apn1.getNetworkTypeBitmask());
1074         apnBuilder.setLingeringNetworkTypeBitmask(apn1.getLingeringNetworkTypeBitmask());
1075         apnBuilder.setProfileId(apn1.getProfileId());
1076         apnBuilder.setPersistent(apn1.isPersistent());
1077         apnBuilder.setMaxConns(apn1.getMaxConns());
1078         apnBuilder.setWaitTime(apn1.getWaitTime());
1079         apnBuilder.setMaxConnsTime(apn1.getMaxConnsTime());
1080         apnBuilder.setApnSetId(apn1.getApnSetId());
1081         apnBuilder.setCarrierId(apn1.getCarrierId());
1082         apnBuilder.setSkip464Xlat(apn1.getSkip464Xlat());
1083         apnBuilder.setAlwaysOn(apn1.isAlwaysOn());
1084         apnBuilder.setInfrastructureBitmask(apn1.getInfrastructureBitmask());
1085         apnBuilder.setEsimBootstrapProvisioning(apn1.isEsimBootstrapProvisioning());
1086 
1087         return new DataProfile.Builder()
1088                 .setApnSetting(apnBuilder.build())
1089                 .setTrafficDescriptor(dp1.getTrafficDescriptor())
1090                 .build();
1091     }
1092 
1093     /**
1094      * Called by {@link DataRetryManager} to clear all permanent failures upon reset.
1095      */
clearAllDataProfilePermanentFailures()1096     public void clearAllDataProfilePermanentFailures() {
1097         mAllDataProfiles.stream()
1098                 .map(DataProfile::getApnSetting)
1099                 .filter(Objects::nonNull)
1100                 .forEach(apnSetting -> apnSetting.setPermanentFailed(false));
1101     }
1102 
1103     /**
1104      * Check if the provided data profile is still compatible with the current environment. Note
1105      * this method ignores APN id check and traffic descriptor check. A data profile with traffic
1106      * descriptor only can always be used in any condition.
1107      *
1108      * @param dataProfile The data profile to check.
1109      * @return {@code true} if the provided data profile can be still used in current environment.
1110      */
isDataProfileCompatible(@onNull DataProfile dataProfile)1111     public boolean isDataProfileCompatible(@NonNull DataProfile dataProfile) {
1112         if (dataProfile.getApnSetting() == null && dataProfile.getTrafficDescriptor() != null) {
1113             // A traffic descriptor only data profile can be always used. Traffic descriptors are
1114             // always generated on the fly instead loaded from the database.
1115             return true;
1116         }
1117 
1118         // Check the APN from the profile is compatible and matches preferred data profile set id.
1119         return mAllDataProfiles.stream()
1120                 .filter(dp -> dp.getApnSetting() != null
1121                         && (dp.getApnSetting().getApnSetId()
1122                         == Telephony.Carriers.MATCH_ALL_APN_SET_ID
1123                         || dp.getApnSetting().getApnSetId() == mPreferredDataProfileSetId))
1124                 .anyMatch(dp -> areDataProfilesSharingApn(dataProfile, dp));
1125     }
1126 
1127     /**
1128      * @return {@code true} if both data profiles' APN setting are non-null and essentially the same
1129      * (non-essential elements include e.g.APN Id).
1130      */
areDataProfilesSharingApn(@ullable DataProfile a, @Nullable DataProfile b)1131     public boolean areDataProfilesSharingApn(@Nullable DataProfile a, @Nullable DataProfile b) {
1132         return a != null
1133                 && b != null
1134                 && a.getApnSetting() != null
1135                 && a.getApnSetting().equals(b.getApnSetting(),
1136                 mPhone.getServiceState().getDataRoamingFromRegistration());
1137     }
1138 
1139     /**
1140      * Register the callback for receiving information from {@link DataProfileManager}.
1141      *
1142      * @param callback The callback.
1143      */
registerCallback(@onNull DataProfileManagerCallback callback)1144     public void registerCallback(@NonNull DataProfileManagerCallback callback) {
1145         mDataProfileManagerCallbacks.add(callback);
1146     }
1147 
1148     /**
1149      * Unregister the previously registered {@link DataProfileManagerCallback}.
1150      *
1151      * @param callback The callback to unregister.
1152      */
unregisterCallback(@onNull DataProfileManagerCallback callback)1153     public void unregisterCallback(@NonNull DataProfileManagerCallback callback) {
1154         mDataProfileManagerCallbacks.remove(callback);
1155     }
1156 
1157     /**
1158      * Trigger the anomaly report with the specified UUID.
1159      *
1160      * @param anomalyMsg Description of the event
1161      * @param uuid UUID associated with that event
1162      */
reportAnomaly(@onNull String anomalyMsg, @NonNull String uuid)1163     private void reportAnomaly(@NonNull String anomalyMsg, @NonNull String uuid) {
1164         logl(anomalyMsg);
1165         AnomalyReporter.reportAnomaly(UUID.fromString(uuid), anomalyMsg, mPhone.getCarrierId());
1166     }
1167 
1168     /**
1169      * Log debug messages.
1170      * @param s debug messages
1171      */
log(@onNull String s)1172     private void log(@NonNull String s) {
1173         Rlog.d(mLogTag, s);
1174     }
1175 
1176     /**
1177      * Log error messages.
1178      * @param s error messages
1179      */
loge(@onNull String s)1180     private void loge(@NonNull String s) {
1181         Rlog.e(mLogTag, s);
1182     }
1183 
1184     /**
1185      * Log verbose messages.
1186      * @param s debug messages.
1187      */
logv(@onNull String s)1188     private void logv(@NonNull String s) {
1189         if (VDBG) Rlog.v(mLogTag, s);
1190     }
1191 
1192     /**
1193      * Log debug messages and also log into the local log.
1194      * @param s debug messages
1195      */
logl(@onNull String s)1196     private void logl(@NonNull String s) {
1197         log(s);
1198         mLocalLog.log(s);
1199     }
1200 
1201     /**
1202      * Dump the state of DataProfileManager
1203      *
1204      * @param fd File descriptor
1205      * @param printWriter Print writer
1206      * @param args Arguments
1207      */
dump(FileDescriptor fd, PrintWriter printWriter, String[] args)1208     public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
1209         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
1210         pw.println(DataProfileManager.class.getSimpleName() + "-" + mPhone.getPhoneId() + ":");
1211         pw.increaseIndent();
1212 
1213         pw.println("Data profiles for the current carrier:");
1214         pw.increaseIndent();
1215         for (DataProfile dp : mAllDataProfiles) {
1216             pw.print(dp);
1217             pw.println(", last setup time: " + DataUtils.elapsedTimeToString(
1218                     dp.getLastSetupTimestamp()));
1219         }
1220         pw.decreaseIndent();
1221 
1222         pw.println("Preferred data profile=" + mPreferredDataProfile);
1223         pw.println("Preferred data profile from db=" + getPreferredDataProfileFromDb());
1224         pw.println("Preferred data profile from config=" + getPreferredDataProfileFromConfig());
1225         pw.println("Preferred data profile set id=" + mPreferredDataProfileSetId);
1226         pw.println("Last internet data profile for=");
1227         pw.increaseIndent();
1228         mLastInternetDataProfiles.snapshot().forEach((key, value) -> pw.println(key + ":" + value));
1229         pw.decreaseIndent();
1230         pw.println("Initial attach data profile=" + mInitialAttachDataProfile);
1231         pw.println("isTetheringDataProfileExisting=" + isTetheringDataProfileExisting(
1232                 TelephonyManager.NETWORK_TYPE_LTE));
1233         pw.println("Permanent failed profiles=");
1234         pw.increaseIndent();
1235         mAllDataProfiles.stream()
1236                 .filter(dp -> dp.getApnSetting() != null && dp.getApnSetting().getPermanentFailed())
1237                 .forEach(pw::println);
1238         pw.decreaseIndent();
1239 
1240         pw.println("Local logs:");
1241         pw.increaseIndent();
1242         mLocalLog.dump(fd, pw, args);
1243         pw.decreaseIndent();
1244         pw.decreaseIndent();
1245     }
1246 }
1247