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