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