1 /*
2  * Copyright (c) 2015, 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.phone;
18 
19 import static android.content.pm.PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION;
20 import static android.service.carrier.CarrierService.ICarrierServiceWrapper.KEY_CONFIG_BUNDLE;
21 import static android.service.carrier.CarrierService.ICarrierServiceWrapper.RESULT_ERROR;
22 import static android.telephony.TelephonyManager.ENABLE_FEATURE_MAPPING;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.app.AppOpsManager;
27 import android.app.compat.CompatChanges;
28 import android.content.BroadcastReceiver;
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.content.ServiceConnection;
34 import android.content.SharedPreferences;
35 import android.content.pm.PackageInfo;
36 import android.content.pm.PackageManager;
37 import android.os.Binder;
38 import android.os.Build;
39 import android.os.Bundle;
40 import android.os.Handler;
41 import android.os.HandlerExecutor;
42 import android.os.IBinder;
43 import android.os.Looper;
44 import android.os.Message;
45 import android.os.PermissionEnforcer;
46 import android.os.PersistableBundle;
47 import android.os.Process;
48 import android.os.RemoteException;
49 import android.os.ResultReceiver;
50 import android.os.SystemProperties;
51 import android.os.UserHandle;
52 import android.preference.PreferenceManager;
53 import android.service.carrier.CarrierIdentifier;
54 import android.service.carrier.CarrierService;
55 import android.service.carrier.ICarrierService;
56 import android.telephony.AnomalyReporter;
57 import android.telephony.CarrierConfigManager;
58 import android.telephony.SubscriptionManager;
59 import android.telephony.TelephonyFrameworkInitializer;
60 import android.telephony.TelephonyManager;
61 import android.telephony.TelephonyRegistryManager;
62 import android.text.TextUtils;
63 import android.util.ArraySet;
64 import android.util.LocalLog;
65 import android.util.Log;
66 
67 import com.android.internal.annotations.VisibleForTesting;
68 import com.android.internal.telephony.ICarrierConfigLoader;
69 import com.android.internal.telephony.IccCardConstants;
70 import com.android.internal.telephony.Phone;
71 import com.android.internal.telephony.PhoneConfigurationManager;
72 import com.android.internal.telephony.PhoneFactory;
73 import com.android.internal.telephony.TelephonyPermissions;
74 import com.android.internal.telephony.flags.FeatureFlags;
75 import com.android.internal.telephony.subscription.SubscriptionManagerService;
76 import com.android.internal.telephony.util.ArrayUtils;
77 import com.android.internal.telephony.util.TelephonyUtils;
78 import com.android.internal.util.IndentingPrintWriter;
79 
80 import java.io.File;
81 import java.io.FileDescriptor;
82 import java.io.FileInputStream;
83 import java.io.FileNotFoundException;
84 import java.io.FileOutputStream;
85 import java.io.FilenameFilter;
86 import java.io.IOException;
87 import java.io.PrintWriter;
88 import java.nio.file.Files;
89 import java.nio.file.Paths;
90 import java.nio.file.attribute.BasicFileAttributes;
91 import java.text.SimpleDateFormat;
92 import java.util.ArrayList;
93 import java.util.Arrays;
94 import java.util.Collections;
95 import java.util.List;
96 import java.util.Locale;
97 import java.util.Objects;
98 import java.util.Set;
99 import java.util.UUID;
100 import java.util.stream.Collectors;
101 import java.util.stream.Stream;
102 
103 /**
104  * CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays.
105  */
106 public class CarrierConfigLoader extends ICarrierConfigLoader.Stub {
107     private static final String LOG_TAG = "CarrierConfigLoader";
108 
109     private static final SimpleDateFormat TIME_FORMAT =
110             new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
111 
112     // Package name for platform carrier config app, bundled with system image.
113     @NonNull private final String mPlatformCarrierConfigPackage;
114 
115     /** The singleton instance. */
116     @Nullable private static CarrierConfigLoader sInstance;
117     // The context for phone app, passed from PhoneGlobals.
118     @NonNull private Context mContext;
119 
120     // All the states below (array indexed by phoneId) are non-null. But the member of the array
121     // is nullable, when e.g. the config for the phone is not loaded yet
122     // Carrier configs from default app, indexed by phoneID.
123     @NonNull private PersistableBundle[] mConfigFromDefaultApp;
124     // Carrier configs from privileged carrier config app, indexed by phoneID.
125     @NonNull private PersistableBundle[] mConfigFromCarrierApp;
126     // Persistent Carrier configs that are provided via the override test API, indexed by phone ID.
127     @NonNull private PersistableBundle[] mPersistentOverrideConfigs;
128     // Carrier configs that are provided via the override test API, indexed by phone ID.
129     @NonNull private PersistableBundle[] mOverrideConfigs;
130     // Carrier configs to override code default when there is no SIM inserted
131     @NonNull private PersistableBundle mNoSimConfig;
132     // Service connection for binding to config app.
133     @NonNull private CarrierServiceConnection[] mServiceConnection;
134     // Service connection for binding to carrier config app for no SIM config.
135     @NonNull private CarrierServiceConnection[] mServiceConnectionForNoSimConfig;
136     // Whether we are bound to a service for each phone
137     @NonNull private boolean[] mServiceBound;
138     // Whether we are bound to a service for no SIM config
139     @NonNull private boolean[] mServiceBoundForNoSimConfig;
140     // Whether we have sent config change broadcast for each phone id.
141     @NonNull private boolean[] mHasSentConfigChange;
142     // Whether the broadcast was sent from EVENT_SYSTEM_UNLOCKED, to track rebroadcasts
143     @NonNull private boolean[] mFromSystemUnlocked;
144     // CarrierService change monitoring
145     @NonNull private CarrierServiceChangeCallback[] mCarrierServiceChangeCallbacks;
146 
147     // Broadcast receiver for system events
148     @NonNull
149     private final BroadcastReceiver mSystemBroadcastReceiver = new ConfigLoaderBroadcastReceiver();
150     @NonNull private final LocalLog mCarrierConfigLoadingLog = new LocalLog(256);
151     // Number of phone instances (active modem count)
152     private int mNumPhones;
153 
154 
155     // Message codes; see mHandler below.
156     // Request from UiccController when SIM becomes absent or error.
157     private static final int EVENT_CLEAR_CONFIG = 0;
158     // Has connected to default app.
159     private static final int EVENT_CONNECTED_TO_DEFAULT = 3;
160     // Has connected to carrier app.
161     private static final int EVENT_CONNECTED_TO_CARRIER = 4;
162     // Config has been loaded from default app (or cache).
163     private static final int EVENT_FETCH_DEFAULT_DONE = 5;
164     // Config has been loaded from carrier app (or cache).
165     private static final int EVENT_FETCH_CARRIER_DONE = 6;
166     // Attempt to fetch from default app or read from XML.
167     private static final int EVENT_DO_FETCH_DEFAULT = 7;
168     // Attempt to fetch from carrier app or read from XML.
169     private static final int EVENT_DO_FETCH_CARRIER = 8;
170     // A package has been installed, uninstalled, or updated.
171     private static final int EVENT_PACKAGE_CHANGED = 9;
172     // Bind timed out for the default app.
173     private static final int EVENT_BIND_DEFAULT_TIMEOUT = 10;
174     // Bind timed out for a carrier app.
175     private static final int EVENT_BIND_CARRIER_TIMEOUT = 11;
176     // Check if the system fingerprint has changed.
177     private static final int EVENT_CHECK_SYSTEM_UPDATE = 12;
178     // Rerun carrier config binding after system is unlocked.
179     private static final int EVENT_SYSTEM_UNLOCKED = 13;
180     // Fetching config timed out from the default app.
181     private static final int EVENT_FETCH_DEFAULT_TIMEOUT = 14;
182     // Fetching config timed out from a carrier app.
183     private static final int EVENT_FETCH_CARRIER_TIMEOUT = 15;
184     // SubscriptionManagerService has finished updating the sub for the carrier config.
185     private static final int EVENT_SUBSCRIPTION_INFO_UPDATED = 16;
186     // Multi-SIM config changed.
187     private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 17;
188     // Attempt to fetch from default app or read from XML for no SIM case.
189     private static final int EVENT_DO_FETCH_DEFAULT_FOR_NO_SIM_CONFIG = 18;
190     // No SIM config has been loaded from default app (or cache).
191     private static final int EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE = 19;
192     // Has connected to default app for no SIM config.
193     private static final int EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG = 20;
194     // Bind timed out for the default app when trying to fetch no SIM config.
195     private static final int EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT = 21;
196     // Fetching config timed out from the default app for no SIM config.
197     private static final int EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT = 22;
198     // NOTE: any new EVENT_* values must be added to method eventToString().
199 
200     private static final int BIND_TIMEOUT_MILLIS = 30000;
201 
202     // Keys used for saving and restoring config bundle from file.
203     private static final String KEY_VERSION = "__carrier_config_package_version__";
204 
205     private static final String OVERRIDE_PACKAGE_ADDITION = "-override";
206 
207     // SharedPreferences key for last known build fingerprint.
208     private static final String KEY_FINGERPRINT = "build_fingerprint";
209 
210     // Argument for #dump that indicates we should also call the default and specified carrier
211     // service's #dump method. In multi-SIM devices, it's possible that carrier A is on SIM 1 and
212     // carrier B is on SIM 2, in which case we should not dump carrier B's service when carrier A
213     // requested the dump.
214     private static final String DUMP_ARG_REQUESTING_PACKAGE = "--requesting-package";
215 
216     // Configs that should always be included when clients calls getConfig[ForSubId] with specified
217     // keys (even configs are not explicitly specified). Those configs have special purpose for the
218     // carrier config APIs to work correctly.
219     private static final String[] CONFIG_SUBSET_METADATA_KEYS = new String[] {
220             CarrierConfigManager.KEY_CARRIER_CONFIG_VERSION_STRING,
221             CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL
222     };
223 
224     // UUID to report anomaly when config changed reported with subId that map to invalid phone
225     private static final String UUID_NOTIFY_CONFIG_CHANGED_WITH_INVALID_PHONE =
226             "d81cef11-c2f1-4d76-955d-7f50e8590c48";
227 
228     // Handler to process various events.
229     //
230     // For each phoneId, the event sequence should be:
231     //     fetch default, connected to default, fetch default (async), fetch default done,
232     //     fetch carrier, connected to carrier, fetch carrier (async), fetch carrier done.
233     //
234     // If there is a saved config file for either the default app or the carrier app, we skip
235     // binding to the app and go straight from fetch to loaded.
236     //
237     // At any time, at most one connection is active. If events are not in this order, previous
238     // connection will be unbound, so only latest event takes effect.
239     //
240     // We broadcast ACTION_CARRIER_CONFIG_CHANGED after:
241     // 1. loading from carrier app (even if read from a file)
242     // 2. loading from default app if there is no carrier app (even if read from a file)
243     // 3. clearing config (e.g. due to sim removal)
244     // 4. encountering bind or IPC error
245     private class ConfigHandler extends Handler {
ConfigHandler(@onNull Looper looper)246         ConfigHandler(@NonNull Looper looper) {
247             super(looper);
248         }
249 
250         @Override
handleMessage(@onNull Message msg)251         public void handleMessage(@NonNull Message msg) {
252             final int phoneId = msg.arg1;
253             logd(eventToString(msg.what) + " phoneId: " + phoneId);
254             if (!SubscriptionManager.isValidPhoneId(phoneId)
255                     && msg.what != EVENT_MULTI_SIM_CONFIG_CHANGED) {
256                 return;
257             }
258             switch (msg.what) {
259                 case EVENT_CLEAR_CONFIG: {
260                     clearConfigForPhone(phoneId, true);
261                     break;
262                 }
263 
264                 case EVENT_SYSTEM_UNLOCKED: {
265                     for (int i = 0; i < mNumPhones; ++i) {
266                         // When the user unlocks the device, send the broadcast again (with a
267                         // rebroadcast extra) if we have sent it before unlock. This will avoid
268                         // trying to load the carrier config when the SIM is still loading when the
269                         // unlock happens.
270                         if (mHasSentConfigChange[i]) {
271                             logdWithLocalLog("System unlocked");
272                             mFromSystemUnlocked[i] = true;
273                             updateConfigForPhoneId(i);
274                         }
275                     }
276                     break;
277                 }
278 
279                 case EVENT_PACKAGE_CHANGED: {
280                     final String carrierPackageName = (String) msg.obj;
281                     // Always clear up the cache and re-load config from scratch since the carrier
282                     // service change is reliable and specific to the phoneId now.
283                     clearCachedConfigForPackage(carrierPackageName);
284                     logdWithLocalLog("Package changed: " + carrierPackageName
285                             + ", phone=" + phoneId);
286                     updateConfigForPhoneId(phoneId);
287                     break;
288                 }
289 
290                 case EVENT_DO_FETCH_DEFAULT: {
291                     // Clear in-memory cache for carrier app config, so when carrier app gets
292                     // uninstalled, no stale config is left.
293                     if (mConfigFromCarrierApp[phoneId] != null
294                             && getCarrierPackageForPhoneId(phoneId) == null) {
295                         mConfigFromCarrierApp[phoneId] = null;
296                     }
297                     // Restore persistent override values.
298                     PersistableBundle config = restoreConfigFromXml(
299                             mPlatformCarrierConfigPackage, OVERRIDE_PACKAGE_ADDITION, phoneId);
300                     if (config != null) {
301                         mPersistentOverrideConfigs[phoneId] = config;
302                     }
303 
304                     config = restoreConfigFromXml(mPlatformCarrierConfigPackage, "", phoneId);
305                     if (config != null) {
306                         mConfigFromDefaultApp[phoneId] = config;
307                         Message newMsg = obtainMessage(EVENT_FETCH_DEFAULT_DONE, phoneId, -1);
308                         newMsg.getData().putBoolean("loaded_from_xml", true);
309                         mHandler.sendMessage(newMsg);
310                     } else {
311                         // No cached config, so fetch it from the default app.
312                         if (bindToConfigPackage(
313                                 mPlatformCarrierConfigPackage,
314                                 phoneId,
315                                 EVENT_CONNECTED_TO_DEFAULT)) {
316                             sendMessageDelayed(
317                                     obtainMessage(EVENT_BIND_DEFAULT_TIMEOUT, phoneId, -1 /*arg2*/,
318                                             getMessageToken(phoneId)),
319                                     BIND_TIMEOUT_MILLIS);
320                         } else {
321                             // Put a stub bundle in place so that the rest of the logic continues
322                             // smoothly.
323                             mConfigFromDefaultApp[phoneId] = new PersistableBundle();
324                             // Send broadcast if bind fails.
325                             updateSubscriptionDatabase(phoneId);
326                             // TODO: We *must* call unbindService even if bindService returns false.
327                             // (And possibly if SecurityException was thrown.)
328                             loge("binding to default app: "
329                                     + mPlatformCarrierConfigPackage + " fails");
330                         }
331                     }
332                     break;
333                 }
334 
335                 case EVENT_CONNECTED_TO_DEFAULT: {
336                     removeMessages(EVENT_BIND_DEFAULT_TIMEOUT, getMessageToken(phoneId));
337                     final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
338                     // If new service connection has been created, unbind.
339                     if (mServiceConnection[phoneId] != conn || conn.service == null) {
340                         unbindIfBound(mContext, conn, phoneId);
341                         break;
342                     }
343                     final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
344                     // ResultReceiver callback will execute in this Handler's thread.
345                     final ResultReceiver resultReceiver =
346                             new ResultReceiver(this) {
347                                 @Override
348                                 public void onReceiveResult(int resultCode, Bundle resultData) {
349                                     unbindIfBound(mContext, conn, phoneId);
350                                     removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT,
351                                             getMessageToken(phoneId));
352                                     // If new service connection has been created, this is stale.
353                                     if (mServiceConnection[phoneId] != conn) {
354                                         loge("Received response for stale request.");
355                                         return;
356                                     }
357                                     if (resultCode == RESULT_ERROR || resultData == null) {
358                                         // On error, abort config fetching.
359                                         loge("Failed to get carrier config");
360                                         updateSubscriptionDatabase(phoneId);
361                                         return;
362                                     }
363                                     PersistableBundle config =
364                                             resultData.getParcelable(KEY_CONFIG_BUNDLE);
365                                     saveConfigToXml(mPlatformCarrierConfigPackage, "", phoneId,
366                                             carrierId, config);
367                                     mConfigFromDefaultApp[phoneId] = config;
368                                     sendMessage(
369                                             obtainMessage(
370                                                     EVENT_FETCH_DEFAULT_DONE, phoneId, -1));
371                                 }
372                             };
373                     // Now fetch the config asynchronously from the ICarrierService.
374                     try {
375                         ICarrierService carrierService =
376                                 ICarrierService.Stub.asInterface(conn.service);
377                         carrierService.getCarrierConfig(phoneId, carrierId, resultReceiver);
378                         logdWithLocalLog("Fetch config for default app: "
379                                 + mPlatformCarrierConfigPackage
380                                 + ", carrierId=" + carrierId.getSpecificCarrierId());
381                     } catch (RemoteException e) {
382                         loge("Failed to get carrier config from default app: " +
383                                 mPlatformCarrierConfigPackage + " err: " + e);
384                         unbindIfBound(mContext, conn, phoneId);
385                         break; // So we don't set a timeout.
386                     }
387                     sendMessageDelayed(
388                             obtainMessage(EVENT_FETCH_DEFAULT_TIMEOUT, phoneId, -1 /*arg2*/,
389                                     getMessageToken(phoneId)),
390                             BIND_TIMEOUT_MILLIS);
391                     break;
392                 }
393 
394                 case EVENT_BIND_DEFAULT_TIMEOUT:
395                 case EVENT_FETCH_DEFAULT_TIMEOUT: {
396                     loge("Bind/fetch time out from " + mPlatformCarrierConfigPackage);
397                     removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT, getMessageToken(phoneId));
398                     // If we attempted to bind to the app, but the service connection is null due to
399                     // the race condition that clear config event happens before bind/fetch complete
400                     // then config was cleared while we were waiting and we should not continue.
401                     if (mServiceConnection[phoneId] != null) {
402                         // If a ResponseReceiver callback is in the queue when this happens, we will
403                         // unbind twice and throw an exception.
404                         unbindIfBound(mContext, mServiceConnection[phoneId], phoneId);
405                         broadcastConfigChangedIntent(phoneId);
406                     }
407                     // Put a stub bundle in place so that the rest of the logic continues smoothly.
408                     mConfigFromDefaultApp[phoneId] = new PersistableBundle();
409                     updateSubscriptionDatabase(phoneId);
410                     break;
411                 }
412 
413                 case EVENT_FETCH_DEFAULT_DONE: {
414                     // If we attempted to bind to the app, but the service connection is null, then
415                     // config was cleared while we were waiting and we should not continue.
416                     if (!msg.getData().getBoolean("loaded_from_xml", false)
417                             && mServiceConnection[phoneId] == null) {
418                         break;
419                     }
420                     final String carrierPackageName = getCarrierPackageForPhoneId(phoneId);
421                     if (carrierPackageName != null) {
422                         logd("Found carrier config app: " + carrierPackageName);
423                         sendMessage(obtainMessage(EVENT_DO_FETCH_CARRIER, phoneId, -1));
424                     } else {
425                         updateSubscriptionDatabase(phoneId);
426                     }
427                     break;
428                 }
429 
430                 case EVENT_DO_FETCH_CARRIER: {
431                     final String carrierPackageName = getCarrierPackageForPhoneId(phoneId);
432                     final PersistableBundle config =
433                             restoreConfigFromXml(carrierPackageName, "", phoneId);
434                     if (config != null) {
435                         mConfigFromCarrierApp[phoneId] = config;
436                         Message newMsg = obtainMessage(EVENT_FETCH_CARRIER_DONE, phoneId, -1);
437                         newMsg.getData().putBoolean("loaded_from_xml", true);
438                         sendMessage(newMsg);
439                     } else {
440                         // No cached config, so fetch it from a carrier app.
441                         if (carrierPackageName != null && bindToConfigPackage(carrierPackageName,
442                                 phoneId, EVENT_CONNECTED_TO_CARRIER)) {
443                             sendMessageDelayed(
444                                     obtainMessage(EVENT_BIND_CARRIER_TIMEOUT, phoneId, -1 /*arg2*/,
445                                             getMessageToken(phoneId)),
446                                     BIND_TIMEOUT_MILLIS);
447                         } else {
448                             // Put a stub bundle in place so that the rest of the logic continues
449                             // smoothly.
450                             mConfigFromCarrierApp[phoneId] = new PersistableBundle();
451                             // Send broadcast if bind fails.
452                             broadcastConfigChangedIntent(phoneId);
453                             loge("Bind to carrier app: " + carrierPackageName + " fails");
454                             updateSubscriptionDatabase(phoneId);
455                         }
456                     }
457                     break;
458                 }
459 
460                 case EVENT_CONNECTED_TO_CARRIER: {
461                     removeMessages(EVENT_BIND_CARRIER_TIMEOUT, getMessageToken(phoneId));
462                     final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
463                     // If new service connection has been created, unbind.
464                     if (mServiceConnection[phoneId] != conn || conn.service == null) {
465                         unbindIfBound(mContext, conn, phoneId);
466                         break;
467                     }
468                     final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
469                     // ResultReceiver callback will execute in this Handler's thread.
470                     final ResultReceiver resultReceiver =
471                             new ResultReceiver(this) {
472                                 @Override
473                                 public void onReceiveResult(int resultCode, Bundle resultData) {
474                                     unbindIfBound(mContext, conn, phoneId);
475                                     removeMessages(EVENT_FETCH_CARRIER_TIMEOUT,
476                                             getMessageToken(phoneId));
477                                     // If new service connection has been created, this is stale.
478                                     if (mServiceConnection[phoneId] != conn) {
479                                         loge("Received response for stale request.");
480                                         return;
481                                     }
482                                     if (resultCode == RESULT_ERROR || resultData == null) {
483                                         // On error, abort config fetching.
484                                         loge("Failed to get carrier config from carrier app: "
485                                                 + getCarrierPackageForPhoneId(phoneId));
486                                         broadcastConfigChangedIntent(phoneId);
487                                         updateSubscriptionDatabase(phoneId);
488                                         return;
489                                     }
490                                     PersistableBundle config =
491                                             resultData.getParcelable(KEY_CONFIG_BUNDLE);
492                                     saveConfigToXml(getCarrierPackageForPhoneId(phoneId), "",
493                                             phoneId, carrierId, config);
494                                     if (config != null) {
495                                         mConfigFromCarrierApp[phoneId] = config;
496                                     } else {
497                                         logdWithLocalLog("Config from carrier app is null "
498                                                 + "for phoneId " + phoneId);
499                                         // Put a stub bundle in place so that the rest of the logic
500                                         // continues smoothly.
501                                         mConfigFromCarrierApp[phoneId] = new PersistableBundle();
502                                     }
503                                     sendMessage(
504                                             obtainMessage(
505                                                     EVENT_FETCH_CARRIER_DONE, phoneId, -1));
506                                 }
507                             };
508                     // Now fetch the config asynchronously from the ICarrierService.
509                     try {
510                         ICarrierService carrierService =
511                                 ICarrierService.Stub.asInterface(conn.service);
512                         carrierService.getCarrierConfig(phoneId, carrierId, resultReceiver);
513                         logdWithLocalLog("Fetch config for carrier app: "
514                                 + getCarrierPackageForPhoneId(phoneId)
515                                 + ", carrierId=" + carrierId.getSpecificCarrierId());
516                     } catch (RemoteException e) {
517                         loge("Failed to get carrier config: " + e);
518                         unbindIfBound(mContext, conn, phoneId);
519                         break; // So we don't set a timeout.
520                     }
521                     sendMessageDelayed(
522                             obtainMessage(EVENT_FETCH_CARRIER_TIMEOUT, phoneId, -1 /*arg2*/,
523                                     getMessageToken(phoneId)),
524                             BIND_TIMEOUT_MILLIS);
525                     break;
526                 }
527 
528                 case EVENT_BIND_CARRIER_TIMEOUT:
529                 case EVENT_FETCH_CARRIER_TIMEOUT: {
530                     loge("Bind/fetch from carrier app timeout, package="
531                             + getCarrierPackageForPhoneId(phoneId));
532                     removeMessages(EVENT_FETCH_CARRIER_TIMEOUT, getMessageToken(phoneId));
533                     // If we attempted to bind to the app, but the service connection is null due to
534                     // the race condition that clear config event happens before bind/fetch complete
535                     // then config was cleared while we were waiting and we should not continue.
536                     if (mServiceConnection[phoneId] != null) {
537                         // If a ResponseReceiver callback is in the queue when this happens, we will
538                         // unbind twice and throw an exception.
539                         unbindIfBound(mContext, mServiceConnection[phoneId], phoneId);
540                         broadcastConfigChangedIntent(phoneId);
541                     }
542                     // Put a stub bundle in place so that the rest of the logic continues smoothly.
543                     mConfigFromCarrierApp[phoneId] = new PersistableBundle();
544                     updateSubscriptionDatabase(phoneId);
545                     break;
546                 }
547                 case EVENT_FETCH_CARRIER_DONE: {
548                     // If we attempted to bind to the app, but the service connection is null, then
549                     // config was cleared while we were waiting and we should not continue.
550                     if (!msg.getData().getBoolean("loaded_from_xml", false)
551                             && mServiceConnection[phoneId] == null) {
552                         break;
553                     }
554                     updateSubscriptionDatabase(phoneId);
555                     break;
556                 }
557 
558                 case EVENT_CHECK_SYSTEM_UPDATE: {
559                     SharedPreferences sharedPrefs =
560                             PreferenceManager.getDefaultSharedPreferences(mContext);
561                     final String lastFingerprint = sharedPrefs.getString(KEY_FINGERPRINT, null);
562                     if (!Build.FINGERPRINT.equals(lastFingerprint)) {
563                         logd(
564                                 "Build fingerprint changed. old: "
565                                         + lastFingerprint
566                                         + " new: "
567                                         + Build.FINGERPRINT);
568                         clearCachedConfigForPackage(null);
569                         sharedPrefs
570                                 .edit()
571                                 .putString(KEY_FINGERPRINT, Build.FINGERPRINT)
572                                 .apply();
573                     }
574                     break;
575                 }
576 
577                 case EVENT_SUBSCRIPTION_INFO_UPDATED:
578                     broadcastConfigChangedIntent(phoneId);
579                     break;
580                 case EVENT_MULTI_SIM_CONFIG_CHANGED:
581                     onMultiSimConfigChanged();
582                     break;
583 
584                 case EVENT_DO_FETCH_DEFAULT_FOR_NO_SIM_CONFIG: {
585                     PersistableBundle config =
586                             restoreNoSimConfigFromXml(mPlatformCarrierConfigPackage);
587 
588                     if (config != null) {
589                         mNoSimConfig = config;
590                         sendMessage(
591                                 obtainMessage(
592                                         EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE,
593                                             phoneId, -1));
594                     } else {
595                         // No cached config, so fetch it from the default app.
596                         if (bindToConfigPackage(
597                                 mPlatformCarrierConfigPackage,
598                                 phoneId,
599                                 EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG)) {
600                             sendMessageDelayed(
601                                     obtainMessage(
602                                             EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT,
603                                                 phoneId, -1), BIND_TIMEOUT_MILLIS);
604                         } else {
605                             broadcastConfigChangedIntent(phoneId, false);
606                             // TODO: We *must* call unbindService even if bindService returns false.
607                             // (And possibly if SecurityException was thrown.)
608                             loge("binding to default app to fetch no SIM config: "
609                                     + mPlatformCarrierConfigPackage + " fails");
610                         }
611                     }
612                     break;
613                 }
614 
615                 case EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE: {
616                     broadcastConfigChangedIntent(phoneId, false);
617                     break;
618                 }
619 
620                 case EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT:
621                 case EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT: {
622                     loge("Bind/fetch time out for no SIM config from "
623                             + mPlatformCarrierConfigPackage);
624                     removeMessages(EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT);
625                     // If we attempted to bind to the app, but the service connection is null due to
626                     // the race condition that clear config event happens before bind/fetch complete
627                     // then config was cleared while we were waiting and we should not continue.
628                     if (mServiceConnectionForNoSimConfig[phoneId] != null) {
629                         // If a ResponseReceiver callback is in the queue when this happens, we will
630                         // unbind twice and throw an exception.
631                         unbindIfBoundForNoSimConfig(mContext,
632                                 mServiceConnectionForNoSimConfig[phoneId], phoneId);
633                     }
634                     broadcastConfigChangedIntent(phoneId, false);
635                     break;
636                 }
637 
638                 case EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG: {
639                     removeMessages(EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT);
640                     final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
641                     // If new service connection has been created, unbind.
642                     if (mServiceConnectionForNoSimConfig[phoneId] != conn || conn.service == null) {
643                         unbindIfBoundForNoSimConfig(mContext, conn, phoneId);
644                         break;
645                     }
646 
647                     // ResultReceiver callback will execute in this Handler's thread.
648                     final ResultReceiver resultReceiver =
649                             new ResultReceiver(this) {
650                                 @Override
651                                 public void onReceiveResult(int resultCode, Bundle resultData) {
652                                     unbindIfBoundForNoSimConfig(mContext, conn, phoneId);
653                                     // If new service connection has been created, this is stale.
654                                     if (mServiceConnectionForNoSimConfig[phoneId] != conn) {
655                                         loge("Received response for stale request.");
656                                         return;
657                                     }
658                                     removeMessages(EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT);
659                                     if (resultCode == RESULT_ERROR || resultData == null) {
660                                         // On error, abort config fetching.
661                                         loge("Failed to get no SIM carrier config");
662                                         return;
663                                     }
664                                     PersistableBundle config =
665                                             resultData.getParcelable(KEY_CONFIG_BUNDLE);
666                                     saveNoSimConfigToXml(mPlatformCarrierConfigPackage, config);
667                                     mNoSimConfig = config;
668                                     sendMessage(
669                                             obtainMessage(
670                                                     EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE,
671                                                         phoneId, -1));
672                                 }
673                             };
674                     // Now fetch the config asynchronously from the ICarrierService.
675                     try {
676                         ICarrierService carrierService =
677                                 ICarrierService.Stub.asInterface(conn.service);
678                         carrierService.getCarrierConfig(phoneId, null, resultReceiver);
679                         logdWithLocalLog("Fetch no sim config from default app: "
680                                 + mPlatformCarrierConfigPackage);
681                     } catch (RemoteException e) {
682                         loge("Failed to get no sim carrier config from default app: " +
683                                 mPlatformCarrierConfigPackage + " err: " + e);
684                         unbindIfBoundForNoSimConfig(mContext, conn, phoneId);
685                         break; // So we don't set a timeout.
686                     }
687                     sendMessageDelayed(
688                             obtainMessage(
689                                     EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT,
690                                         phoneId, -1), BIND_TIMEOUT_MILLIS);
691                     break;
692                 }
693             }
694         }
695     }
696 
697     @NonNull private final Handler mHandler;
698 
699     @NonNull private final FeatureFlags  mFeatureFlags;
700 
701     @NonNull private final PackageManager mPackageManager;
702     private final int mVendorApiLevel;
703 
704     /**
705      * Constructs a CarrierConfigLoader, registers it as a service, and registers a broadcast
706      * receiver for relevant events.
707      */
708     @VisibleForTesting
CarrierConfigLoader(@onNull Context context, @NonNull Looper looper, @NonNull FeatureFlags featureFlags)709     /* package */ CarrierConfigLoader(@NonNull Context context, @NonNull Looper looper,
710             @NonNull FeatureFlags featureFlags) {
711         super(PermissionEnforcer.fromContext(context));
712         mContext = context;
713         mPlatformCarrierConfigPackage =
714                 mContext.getString(R.string.platform_carrier_config_package);
715         mHandler = new ConfigHandler(looper);
716 
717         IntentFilter systemEventsFilter = new IntentFilter();
718         systemEventsFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
719         context.registerReceiver(mSystemBroadcastReceiver, systemEventsFilter);
720 
721         mNumPhones = TelephonyManager.from(context).getActiveModemCount();
722         mConfigFromDefaultApp = new PersistableBundle[mNumPhones];
723         mConfigFromCarrierApp = new PersistableBundle[mNumPhones];
724         mPersistentOverrideConfigs = new PersistableBundle[mNumPhones];
725         mOverrideConfigs = new PersistableBundle[mNumPhones];
726         mNoSimConfig = new PersistableBundle();
727         mServiceConnection = new CarrierServiceConnection[mNumPhones];
728         mServiceBound = new boolean[mNumPhones];
729         mHasSentConfigChange = new boolean[mNumPhones];
730         mFromSystemUnlocked = new boolean[mNumPhones];
731         mServiceConnectionForNoSimConfig = new CarrierServiceConnection[mNumPhones];
732         mServiceBoundForNoSimConfig = new boolean[mNumPhones];
733         mCarrierServiceChangeCallbacks = new CarrierServiceChangeCallback[mNumPhones];
734         for (int phoneId = 0; phoneId < mNumPhones; phoneId++) {
735             mCarrierServiceChangeCallbacks[phoneId] = new CarrierServiceChangeCallback(phoneId);
736             TelephonyManager.from(context).registerCarrierPrivilegesCallback(phoneId,
737                     new HandlerExecutor(mHandler), mCarrierServiceChangeCallbacks[phoneId]);
738         }
739         mFeatureFlags = featureFlags;
740         mPackageManager = context.getPackageManager();
741         mVendorApiLevel = SystemProperties.getInt(
742                 "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
743         logd("CarrierConfigLoader has started");
744 
745         PhoneConfigurationManager.registerForMultiSimConfigChange(
746                 mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
747 
748         mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE);
749     }
750 
751     /**
752      * Initialize the singleton CarrierConfigLoader instance.
753      *
754      * This is only done once, at startup, from {@link com.android.phone.PhoneApp#onCreate}.
755      */
756     @NonNull
init(@onNull Context context, @NonNull FeatureFlags featureFlags)757     /* package */ static CarrierConfigLoader init(@NonNull Context context,
758             @NonNull FeatureFlags featureFlags) {
759         synchronized (CarrierConfigLoader.class) {
760             if (sInstance == null) {
761                 sInstance = new CarrierConfigLoader(context, Looper.myLooper(), featureFlags);
762                 // Make this service available through ServiceManager.
763                 TelephonyFrameworkInitializer.getTelephonyServiceManager()
764                         .getCarrierConfigServiceRegisterer().register(sInstance);
765             } else {
766                 Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
767             }
768             return sInstance;
769         }
770     }
771 
772     @VisibleForTesting
clearConfigForPhone(int phoneId, boolean fetchNoSimConfig)773     /* package */ void clearConfigForPhone(int phoneId, boolean fetchNoSimConfig) {
774         /* Ignore clear configuration request if device is being shutdown. */
775         Phone phone = PhoneFactory.getPhone(phoneId);
776         if (phone != null) {
777             if (phone.isShuttingDown()) {
778                 return;
779             }
780         }
781 
782         if (mConfigFromDefaultApp.length <= phoneId) {
783             Log.wtf(LOG_TAG, "Invalid phone id " + phoneId);
784             return;
785         }
786 
787         mConfigFromDefaultApp[phoneId] = null;
788         mConfigFromCarrierApp[phoneId] = null;
789         mServiceConnection[phoneId] = null;
790         mHasSentConfigChange[phoneId] = false;
791 
792         if (fetchNoSimConfig) {
793             // To fetch no SIM config
794             mHandler.sendMessage(
795                     mHandler.obtainMessage(
796                             EVENT_DO_FETCH_DEFAULT_FOR_NO_SIM_CONFIG, phoneId, -1));
797         }
798     }
799 
updateSubscriptionDatabase(int phoneId)800     private void updateSubscriptionDatabase(int phoneId) {
801         logd("updateSubscriptionDatabase: phoneId=" + phoneId);
802         String configPackageName;
803         PersistableBundle configToSend;
804         int carrierId = getSpecificCarrierIdForPhoneId(phoneId);
805         // Prefer the carrier privileged carrier app, but if there is not one, use the platform
806         // default carrier app.
807         if (mConfigFromCarrierApp[phoneId] != null) {
808             configPackageName = getCarrierPackageForPhoneId(phoneId);
809             configToSend = mConfigFromCarrierApp[phoneId];
810         } else {
811             configPackageName = mPlatformCarrierConfigPackage;
812             configToSend = mConfigFromDefaultApp[phoneId];
813         }
814 
815         if (configToSend == null) {
816             configToSend = new PersistableBundle();
817         }
818 
819         // mOverrideConfigs is for testing. And it will override current configs.
820         PersistableBundle config = mOverrideConfigs[phoneId];
821         if (config != null) {
822             configToSend = new PersistableBundle(configToSend);
823             configToSend.putAll(config);
824         }
825 
826         SubscriptionManagerService.getInstance().updateSubscriptionByCarrierConfig(
827                 phoneId, configPackageName, configToSend,
828                 () -> mHandler.obtainMessage(EVENT_SUBSCRIPTION_INFO_UPDATED, phoneId, -1)
829                         .sendToTarget());
830     }
831 
broadcastConfigChangedIntent(int phoneId)832     private void broadcastConfigChangedIntent(int phoneId) {
833         broadcastConfigChangedIntent(phoneId, true);
834     }
835 
broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra)836     private void broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra) {
837         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
838         int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
839         int specificCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
840 
841         Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
842         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
843                 Intent.FLAG_RECEIVER_FOREGROUND);
844         if (addSubIdExtra) {
845             int simApplicationState = getSimApplicationStateForPhone(phoneId);
846             // Include subId/carrier id extra only if SIM records are loaded
847             if (simApplicationState != TelephonyManager.SIM_STATE_UNKNOWN
848                     && simApplicationState != TelephonyManager.SIM_STATE_NOT_READY) {
849                 subId = SubscriptionManager.getSubscriptionId(phoneId);
850                 carrierId = getCarrierIdForPhoneId(phoneId);
851                 specificCarrierId = getSpecificCarrierIdForPhoneId(phoneId);
852                 intent.putExtra(TelephonyManager.EXTRA_SPECIFIC_CARRIER_ID, specificCarrierId);
853                 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
854                 intent.putExtra(TelephonyManager.EXTRA_CARRIER_ID, carrierId);
855             }
856         }
857         intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId);
858         intent.putExtra(CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK,
859                 mFromSystemUnlocked[phoneId]);
860 
861         TelephonyRegistryManager trm = mContext.getSystemService(TelephonyRegistryManager.class);
862         // Unlike broadcast, we wouldn't notify registrants on carrier config change when device is
863         // unlocked. Only real carrier config change will send the notification to registrants.
864         if (trm != null && !mFromSystemUnlocked[phoneId]) {
865             trm.notifyCarrierConfigChanged(phoneId, subId, carrierId, specificCarrierId);
866         }
867 
868         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
869 
870         if (SubscriptionManager.isValidSubscriptionId(subId)) {
871             logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId + ", subId=" + subId);
872         } else {
873             logd("Broadcast CARRIER_CONFIG_CHANGED for phone " + phoneId);
874         }
875         mHasSentConfigChange[phoneId] = true;
876         mFromSystemUnlocked[phoneId] = false;
877     }
878 
getSimApplicationStateForPhone(int phoneId)879     private int getSimApplicationStateForPhone(int phoneId) {
880         int simApplicationState = TelephonyManager.SIM_STATE_UNKNOWN;
881         int subId = SubscriptionManager.getSubscriptionId(phoneId);
882         if (SubscriptionManager.isValidSubscriptionId(subId)) {
883             TelephonyManager telMgr = TelephonyManager.from(mContext)
884                     .createForSubscriptionId(subId);
885             simApplicationState = telMgr.getSimApplicationState();
886         }
887         return simApplicationState;
888     }
889 
890     /** Binds to the default or carrier config app. */
bindToConfigPackage(@onNull String pkgName, int phoneId, int eventId)891     private boolean bindToConfigPackage(@NonNull String pkgName, int phoneId, int eventId) {
892         logdWithLocalLog("Binding to " + pkgName + " for phone " + phoneId);
893         Intent carrierService = new Intent(CarrierService.CARRIER_SERVICE_INTERFACE);
894         carrierService.setPackage(pkgName);
895         CarrierServiceConnection serviceConnection =  new CarrierServiceConnection(
896                 phoneId, pkgName, eventId);
897         if (eventId == EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG) {
898             mServiceConnectionForNoSimConfig[phoneId] = serviceConnection;
899         } else {
900             mServiceConnection[phoneId] = serviceConnection;
901         }
902         try {
903             if (mContext.bindService(carrierService, serviceConnection,
904                     Context.BIND_AUTO_CREATE)) {
905                 if (eventId == EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG) {
906                     mServiceBoundForNoSimConfig[phoneId] = true;
907                 } else {
908                     mServiceBound[phoneId] = true;
909                 }
910                 return true;
911             } else {
912                 return false;
913             }
914         } catch (SecurityException ex) {
915             return false;
916         }
917     }
918 
919     @VisibleForTesting
920     @NonNull
getCarrierIdentifierForPhoneId(int phoneId)921     /* package */ CarrierIdentifier getCarrierIdentifierForPhoneId(int phoneId) {
922         String mcc = "";
923         String mnc = "";
924         String imsi = "";
925         String gid1 = "";
926         String gid2 = "";
927         String spn = TelephonyManager.from(mContext).getSimOperatorNameForPhone(phoneId);
928         String simOperator = TelephonyManager.from(mContext).getSimOperatorNumericForPhone(phoneId);
929         int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
930         int specificCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
931         // A valid simOperator should be 5 or 6 digits, depending on the length of the MNC.
932         if (simOperator != null && simOperator.length() >= 3) {
933             mcc = simOperator.substring(0, 3);
934             mnc = simOperator.substring(3);
935         }
936         Phone phone = PhoneFactory.getPhone(phoneId);
937         if (phone != null) {
938             imsi = phone.getSubscriberId();
939             gid1 = phone.getGroupIdLevel1();
940             gid2 = phone.getGroupIdLevel2();
941             carrierId = phone.getCarrierId();
942             specificCarrierId = phone.getSpecificCarrierId();
943         }
944         return new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2, carrierId, specificCarrierId);
945     }
946 
947     /** Returns the package name of a privileged carrier app, or null if there is none. */
948     @Nullable
getCarrierPackageForPhoneId(int phoneId)949     private String getCarrierPackageForPhoneId(int phoneId) {
950         final long token = Binder.clearCallingIdentity();
951         try {
952             return TelephonyManager.from(mContext)
953                     .getCarrierServicePackageNameForLogicalSlot(phoneId);
954         } finally {
955             Binder.restoreCallingIdentity(token);
956         }
957     }
958 
959     @Nullable
getIccIdForPhoneId(int phoneId)960     private String getIccIdForPhoneId(int phoneId) {
961         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
962             return null;
963         }
964         Phone phone = PhoneFactory.getPhone(phoneId);
965         if (phone == null) {
966             return null;
967         }
968         return phone.getIccSerialNumber();
969     }
970 
971     /**
972      * Get the sim specific carrier id {@link TelephonyManager#getSimSpecificCarrierId()}
973      */
getSpecificCarrierIdForPhoneId(int phoneId)974     private int getSpecificCarrierIdForPhoneId(int phoneId) {
975         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
976             return TelephonyManager.UNKNOWN_CARRIER_ID;
977         }
978         Phone phone = PhoneFactory.getPhone(phoneId);
979         if (phone == null) {
980             return TelephonyManager.UNKNOWN_CARRIER_ID;
981         }
982         return phone.getSpecificCarrierId();
983     }
984 
985     /**
986      * Get the sim carrier id {@link TelephonyManager#getSimCarrierId() }
987      */
getCarrierIdForPhoneId(int phoneId)988     private int getCarrierIdForPhoneId(int phoneId) {
989         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
990             return TelephonyManager.UNKNOWN_CARRIER_ID;
991         }
992         Phone phone = PhoneFactory.getPhone(phoneId);
993         if (phone == null) {
994             return TelephonyManager.UNKNOWN_CARRIER_ID;
995         }
996         return phone.getCarrierId();
997     }
998 
999     /**
1000      * Writes a bundle to an XML file.
1001      *
1002      * The bundle will be written to a file named after the package name, ICCID and
1003      * specific carrier id {@link TelephonyManager#getSimSpecificCarrierId()}. the same carrier
1004      * should have a single copy of XML file named after carrier id. However, it's still possible
1005      * that platform doesn't recognize the current sim carrier, we will use iccid + carrierid as
1006      * the canonical file name. carrierid can also handle the cases SIM OTA resolves to different
1007      * carrier while iccid remains the same.
1008      *
1009      * The file can be restored later with {@link @restoreConfigFromXml}. The XML output will
1010      * include the bundle and the current version of the specified package.
1011      *
1012      * In case of errors or invalid input, no file will be written.
1013      *
1014      * @param packageName   the name of the package from which we fetched this bundle.
1015      * @param extraString   An extra string to be used in the XML file name.
1016      * @param phoneId       the phone ID.
1017      * @param carrierId     contains all carrier-identifying information.
1018      * @param config        the bundle to be written. Null will be treated as an empty bundle.
1019      * @param isNoSimConfig whether this is invoked for noSimConfig or not.
1020      */
saveConfigToXml(@ullable String packageName, @NonNull String extraString, int phoneId, @Nullable CarrierIdentifier carrierId, @NonNull PersistableBundle config, boolean isNoSimConfig)1021     private void saveConfigToXml(@Nullable String packageName, @NonNull String extraString,
1022             int phoneId, @Nullable CarrierIdentifier carrierId, @NonNull PersistableBundle config,
1023             boolean isNoSimConfig) {
1024         if (packageName == null) {
1025             loge("Cannot save config with null packageName. phoneId=" + phoneId);
1026             return;
1027         }
1028 
1029         String fileName;
1030         if (isNoSimConfig) {
1031             fileName = getFilenameForNoSimConfig(packageName);
1032         } else {
1033             if (TelephonyManager.getSimStateForSlotIndex(phoneId)
1034                     != TelephonyManager.SIM_STATE_LOADED) {
1035                 loge("Skip saving config because SIM records are not loaded. phoneId=" + phoneId);
1036                 return;
1037             }
1038 
1039             final String iccid = getIccIdForPhoneId(phoneId);
1040             final int cid = carrierId != null ? carrierId.getSpecificCarrierId()
1041                     : TelephonyManager.UNKNOWN_CARRIER_ID;
1042             if (iccid == null) {
1043                 loge("Cannot save config with null iccid. phoneId=" + phoneId);
1044                 return;
1045             }
1046             fileName = getFilenameForConfig(packageName, extraString, iccid, cid);
1047         }
1048 
1049         // b/32668103 Only save to file if config isn't empty.
1050         // In case of failure, not caching an empty bundle will
1051         // try loading config again on next power on or sim loaded.
1052         // Downside is for genuinely empty bundle, will bind and load
1053         // on every power on.
1054         if (config == null || config.isEmpty()) {
1055             return;
1056         }
1057 
1058         final String version = getPackageVersion(packageName);
1059         if (version == null) {
1060             loge("Failed to get package version for: " + packageName + ", phoneId=" + phoneId);
1061             return;
1062         }
1063 
1064         logdWithLocalLog("Save carrier config to cache. phoneId=" + phoneId
1065                         + ", xml=" + getFilePathForLogging(fileName) + ", version=" + version);
1066 
1067         FileOutputStream outFile = null;
1068         try {
1069             outFile = new FileOutputStream(new File(mContext.getFilesDir(), fileName));
1070             config.putString(KEY_VERSION, version);
1071             config.writeToStream(outFile);
1072             outFile.flush();
1073             outFile.close();
1074         } catch (IOException e) {
1075             loge(e.toString());
1076         }
1077     }
1078 
1079     @VisibleForTesting
saveConfigToXml(@ullable String packageName, @NonNull String extraString, int phoneId, @NonNull CarrierIdentifier carrierId, @NonNull PersistableBundle config)1080     /* package */ void saveConfigToXml(@Nullable String packageName, @NonNull String extraString,
1081             int phoneId, @NonNull CarrierIdentifier carrierId, @NonNull PersistableBundle config) {
1082         saveConfigToXml(packageName, extraString, phoneId, carrierId, config, false);
1083     }
1084 
1085     @VisibleForTesting
saveNoSimConfigToXml(@ullable String packageName, @NonNull PersistableBundle config)1086     /* package */ void saveNoSimConfigToXml(@Nullable String packageName,
1087             @NonNull PersistableBundle config) {
1088         saveConfigToXml(packageName, "", -1, null, config, true);
1089     }
1090 
1091     /**
1092      * Reads a bundle from an XML file.
1093      *
1094      * This restores a bundle that was written with {@link #saveConfigToXml}. This returns the saved
1095      * config bundle for the given package and phone ID.
1096      *
1097      * In case of errors, or if the saved config is from a different package version than the
1098      * current version, then null will be returned.
1099      *
1100      * @param packageName    the name of the package from which we fetched this bundle.
1101      * @param extraString    An extra string to be used in the XML file name.
1102      * @param phoneId        the phone ID.
1103      * @param isNoSimConfig  whether this is invoked for noSimConfig or not.
1104      * @return the bundle from the XML file. Returns null if there is no saved config, the saved
1105      * version does not match, or reading config fails.
1106      */
1107     @Nullable
restoreConfigFromXml(@ullable String packageName, @NonNull String extraString, int phoneId, boolean isNoSimConfig)1108     private PersistableBundle restoreConfigFromXml(@Nullable String packageName,
1109             @NonNull String extraString, int phoneId, boolean isNoSimConfig) {
1110         if (packageName == null) {
1111             loge("Cannot restore config with null packageName");
1112         }
1113         final String version = getPackageVersion(packageName);
1114         if (version == null) {
1115             loge("Failed to get package version for: " + packageName);
1116             return null;
1117         }
1118 
1119         String fileName;
1120         String iccid = null;
1121         if (isNoSimConfig) {
1122             fileName = getFilenameForNoSimConfig(packageName);
1123         } else {
1124             if (TelephonyManager.getSimStateForSlotIndex(phoneId)
1125                     != TelephonyManager.SIM_STATE_LOADED) {
1126                 loge("Skip restore config because SIM records are not loaded. phoneId=" + phoneId);
1127                 return null;
1128             }
1129 
1130             iccid = getIccIdForPhoneId(phoneId);
1131             final int cid = getSpecificCarrierIdForPhoneId(phoneId);
1132             if (iccid == null) {
1133                 loge("Cannot restore config with null iccid. phoneId=" + phoneId);
1134                 return null;
1135             }
1136             fileName = getFilenameForConfig(packageName, extraString, iccid, cid);
1137         }
1138 
1139         PersistableBundle restoredBundle = null;
1140         File file = new File(mContext.getFilesDir(), fileName);
1141         String filePath = file.getPath();
1142         String savedVersion = null;
1143         try (FileInputStream inFile = new FileInputStream(file)) {
1144 
1145             restoredBundle = PersistableBundle.readFromStream(inFile);
1146             savedVersion = restoredBundle.getString(KEY_VERSION);
1147             restoredBundle.remove(KEY_VERSION);
1148 
1149             if (!version.equals(savedVersion)) {
1150                 loge("Saved version mismatch: " + version + " vs " + savedVersion
1151                         + ", phoneId=" + phoneId);
1152                 restoredBundle = null;
1153             }
1154         } catch (FileNotFoundException e) {
1155             // Missing file is normal occurrence that might occur with a new sim or when restoring
1156             // an override file during boot and should not be treated as an error.
1157             if (isNoSimConfig) {
1158                 logd("File not found: " + file.getPath() + ", phoneId=" + phoneId);
1159             } else {
1160                 logd("File not found : " + getFilePathForLogging(filePath, iccid)
1161                         + ", phoneId=" + phoneId);
1162             }
1163         } catch (IOException e) {
1164             loge(e.toString());
1165         }
1166 
1167         if (restoredBundle != null) {
1168             logdWithLocalLog("Restored carrier config from cache. phoneId=" + phoneId + ", xml="
1169                     + getFilePathForLogging(fileName) + ", version=" + savedVersion
1170                     + ", modified time=" + getFileTime(filePath));
1171         }
1172         return restoredBundle;
1173     }
1174 
1175     /**
1176      * This method will mask most part of iccid in the filepath for logging on userbuild
1177      */
1178     @NonNull
getFilePathForLogging(@ullable String filePath, @Nullable String iccid)1179     private String getFilePathForLogging(@Nullable String filePath, @Nullable String iccid) {
1180         // If loggable then return with actual file path
1181         if (TelephonyUtils.IS_DEBUGGABLE) {
1182             return filePath;
1183         }
1184         String path = filePath;
1185         int length = (iccid != null) ? iccid.length() : 0;
1186         if (length > 5 && filePath != null) {
1187             path = filePath.replace(iccid.substring(5), "***************");
1188         }
1189         return path;
1190     }
1191 
1192     @Nullable
restoreConfigFromXml(@ullable String packageName, @NonNull String extraString, int phoneId)1193     private PersistableBundle restoreConfigFromXml(@Nullable String packageName,
1194             @NonNull String extraString, int phoneId) {
1195         return restoreConfigFromXml(packageName, extraString, phoneId, false);
1196     }
1197 
1198     @Nullable
restoreNoSimConfigFromXml(@ullable String packageName)1199     private PersistableBundle restoreNoSimConfigFromXml(@Nullable String packageName) {
1200         return restoreConfigFromXml(packageName, "", -1, true);
1201     }
1202 
1203     /**
1204      * Clears cached carrier config.
1205      * This deletes all saved XML files associated with the given package name. If packageName is
1206      * null, then it deletes all saved XML files.
1207      *
1208      * @param packageName the name of a carrier package, or null if all cached config should be
1209      *                    cleared.
1210      * @return true iff one or more files were deleted.
1211      */
clearCachedConfigForPackage(@ullable final String packageName)1212     private boolean clearCachedConfigForPackage(@Nullable final String packageName) {
1213         File dir = mContext.getFilesDir();
1214         File[] packageFiles = dir.listFiles(new FilenameFilter() {
1215             public boolean accept(File dir, String filename) {
1216                 if (packageName != null) {
1217                     return filename.startsWith("carrierconfig-" + packageName + "-");
1218                 } else {
1219                     return filename.startsWith("carrierconfig-");
1220                 }
1221             }
1222         });
1223         if (packageFiles == null || packageFiles.length < 1) return false;
1224         for (File f : packageFiles) {
1225             logdWithLocalLog("Deleting " + getFilePathForLogging(f.getName()));
1226             f.delete();
1227         }
1228         return true;
1229     }
1230 
getFilePathForLogging(String filePath)1231     private String getFilePathForLogging(String filePath) {
1232         if (!TextUtils.isEmpty(filePath)) {
1233             String[] fileTokens = filePath.split("-");
1234             if (fileTokens != null && fileTokens.length > 2) {
1235                 String iccid = fileTokens[fileTokens.length -2];
1236                 return getFilePathForLogging(filePath, iccid);
1237             }
1238             return filePath;
1239         }
1240         return filePath;
1241     }
1242 
1243     /** Builds a canonical file name for a config file. */
1244     @NonNull
getFilenameForConfig( @onNull String packageName, @NonNull String extraString, @NonNull String iccid, int cid)1245     private static String getFilenameForConfig(
1246             @NonNull String packageName, @NonNull String extraString,
1247             @NonNull String iccid, int cid) {
1248         // the same carrier should have a single copy of XML file named after carrier id.
1249         // However, it's still possible that platform doesn't recognize the current sim carrier,
1250         // we will use iccid + carrierid as the canonical file name. carrierid can also handle the
1251         // cases SIM OTA resolves to different carrier while iccid remains the same.
1252         return "carrierconfig-" + packageName + extraString + "-" + iccid + "-" + cid + ".xml";
1253     }
1254 
1255     /** Builds a canonical file name for no SIM config file. */
1256     @NonNull
getFilenameForNoSimConfig(@onNull String packageName)1257     private String getFilenameForNoSimConfig(@NonNull String packageName) {
1258         return "carrierconfig-" + packageName + "-" + "nosim" + ".xml";
1259     }
1260 
1261     /** Return the current version code of a package, or null if the name is not found. */
1262     @Nullable
getPackageVersion(@onNull String packageName)1263     private String getPackageVersion(@NonNull String packageName) {
1264         try {
1265             PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
1266             return Long.toString(info.getLongVersionCode());
1267         } catch (PackageManager.NameNotFoundException e) {
1268             return null;
1269         }
1270     }
1271 
1272     /**
1273      * Read up to date config.
1274      *
1275      * This reads config bundles for the given phoneId. That means getting the latest bundle from
1276      * the default app and a privileged carrier app, if present. This will not bind to an app if we
1277      * have a saved config file to use instead.
1278      */
updateConfigForPhoneId(int phoneId)1279     private void updateConfigForPhoneId(int phoneId) {
1280         mHandler.sendMessage(mHandler.obtainMessage(EVENT_DO_FETCH_DEFAULT, phoneId, -1));
1281     }
1282 
onMultiSimConfigChanged()1283     private void onMultiSimConfigChanged() {
1284         int oldNumPhones = mNumPhones;
1285         mNumPhones = TelephonyManager.from(mContext).getActiveModemCount();
1286         if (mNumPhones == oldNumPhones) {
1287             return;
1288         }
1289         logdWithLocalLog("mNumPhones change from " + oldNumPhones + " to " + mNumPhones);
1290 
1291         // If DS -> SS switch, release the resources BEFORE truncating the arrays to avoid leaking
1292         for (int phoneId = mNumPhones; phoneId < oldNumPhones; phoneId++) {
1293             if (mServiceConnection[phoneId] != null) {
1294                 unbindIfBound(mContext, mServiceConnection[phoneId], phoneId);
1295             }
1296             if (mServiceConnectionForNoSimConfig[phoneId] != null) {
1297                 unbindIfBoundForNoSimConfig(mContext, mServiceConnectionForNoSimConfig[phoneId],
1298                         phoneId);
1299             }
1300         }
1301 
1302         // The phone to slot mapping may change, unregister here and re-register callbacks later
1303         for (int phoneId = 0; phoneId < oldNumPhones; phoneId++) {
1304             if (mCarrierServiceChangeCallbacks[phoneId] != null) {
1305                 TelephonyManager.from(mContext).unregisterCarrierPrivilegesCallback(
1306                         mCarrierServiceChangeCallbacks[phoneId]);
1307             }
1308         }
1309 
1310         // Copy the original arrays, truncate or padding with zeros (if necessary) to new length
1311         mConfigFromDefaultApp = Arrays.copyOf(mConfigFromDefaultApp, mNumPhones);
1312         mConfigFromCarrierApp = Arrays.copyOf(mConfigFromCarrierApp, mNumPhones);
1313         mPersistentOverrideConfigs = Arrays.copyOf(mPersistentOverrideConfigs, mNumPhones);
1314         mOverrideConfigs = Arrays.copyOf(mOverrideConfigs, mNumPhones);
1315         mServiceConnection = Arrays.copyOf(mServiceConnection, mNumPhones);
1316         mServiceConnectionForNoSimConfig =
1317                 Arrays.copyOf(mServiceConnectionForNoSimConfig, mNumPhones);
1318         mServiceBound = Arrays.copyOf(mServiceBound, mNumPhones);
1319         mServiceBoundForNoSimConfig = Arrays.copyOf(mServiceBoundForNoSimConfig, mNumPhones);
1320         mHasSentConfigChange = Arrays.copyOf(mHasSentConfigChange, mNumPhones);
1321         mFromSystemUnlocked = Arrays.copyOf(mFromSystemUnlocked, mNumPhones);
1322         mCarrierServiceChangeCallbacks = Arrays.copyOf(mCarrierServiceChangeCallbacks, mNumPhones);
1323 
1324         // Load the config for all the phones and re-register callback AFTER padding the arrays.
1325         for (int phoneId = 0; phoneId < mNumPhones; phoneId++) {
1326             updateConfigForPhoneId(phoneId);
1327             mCarrierServiceChangeCallbacks[phoneId] = new CarrierServiceChangeCallback(phoneId);
1328             TelephonyManager.from(mContext).registerCarrierPrivilegesCallback(phoneId,
1329                     new HandlerExecutor(mHandler), mCarrierServiceChangeCallbacks[phoneId]);
1330         }
1331     }
1332 
1333     @Override
1334     @NonNull
getConfigForSubId(int subscriptionId, @NonNull String callingPackage)1335     public PersistableBundle getConfigForSubId(int subscriptionId, @NonNull String callingPackage) {
1336         return getConfigForSubIdWithFeature(subscriptionId, callingPackage, null);
1337     }
1338 
1339     @Override
1340     @NonNull
getConfigForSubIdWithFeature(int subscriptionId, @NonNull String callingPackage, @Nullable String callingFeatureId)1341     public PersistableBundle getConfigForSubIdWithFeature(int subscriptionId,
1342             @NonNull String callingPackage, @Nullable String callingFeatureId) {
1343         if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subscriptionId,
1344                 callingPackage, callingFeatureId, "getCarrierConfig")) {
1345             return new PersistableBundle();
1346         }
1347 
1348         enforceTelephonyFeatureWithException(callingPackage, "getConfigForSubIdWithFeature");
1349 
1350         int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
1351         PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig();
1352         if (SubscriptionManager.isValidPhoneId(phoneId)) {
1353             PersistableBundle config = mConfigFromDefaultApp[phoneId];
1354             if (config != null) {
1355                 retConfig.putAll(config);
1356             }
1357             config = mConfigFromCarrierApp[phoneId];
1358             if (config != null) {
1359                 retConfig.putAll(config);
1360             }
1361             config = mPersistentOverrideConfigs[phoneId];
1362             if (config != null) {
1363                 retConfig.putAll(config);
1364             }
1365             config = mOverrideConfigs[phoneId];
1366             if (config != null) {
1367                 retConfig.putAll(config);
1368             }
1369             // Ignore the theoretical case of the default app not being present since that won't
1370             // work in CarrierConfigLoader today.
1371             final boolean allConfigsApplied =
1372                     (mConfigFromCarrierApp[phoneId] != null
1373                         || getCarrierPackageForPhoneId(phoneId) == null)
1374                     && mConfigFromDefaultApp[phoneId] != null;
1375             retConfig.putBoolean(
1376                     CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, allConfigsApplied);
1377         } else {
1378             if (mNoSimConfig != null) {
1379                 retConfig.putAll(mNoSimConfig);
1380             }
1381         }
1382         return retConfig;
1383     }
1384 
1385     @Override
1386     @NonNull
getConfigSubsetForSubIdWithFeature(int subscriptionId, @NonNull String callingPackage, @Nullable String callingFeatureId, @NonNull String[] keys)1387     public PersistableBundle getConfigSubsetForSubIdWithFeature(int subscriptionId,
1388             @NonNull String callingPackage, @Nullable String callingFeatureId,
1389             @NonNull String[] keys) {
1390         Objects.requireNonNull(callingPackage, "Calling package must be non-null");
1391         Objects.requireNonNull(keys, "Config keys must be non-null");
1392         enforceCallerIsSystemOrRequestingPackage(callingPackage);
1393 
1394         enforceTelephonyFeatureWithException(callingPackage,
1395                 "getConfigSubsetForSubIdWithFeature");
1396 
1397         // Permission check is performed inside and an empty bundle will return on failure.
1398         // No SecurityException thrown here since most clients expect to retrieve the overridden
1399         // value if present or use default one if not
1400         PersistableBundle allConfigs = getConfigForSubIdWithFeature(subscriptionId, callingPackage,
1401                 callingFeatureId);
1402         if (allConfigs.isEmpty()) {
1403             return allConfigs;
1404         }
1405         for (String key : keys) {
1406             Objects.requireNonNull(key, "Config key must be non-null");
1407         }
1408 
1409         PersistableBundle configSubset = new PersistableBundle(
1410                 keys.length + CONFIG_SUBSET_METADATA_KEYS.length);
1411         for (String carrierConfigKey : keys) {
1412             Object value = allConfigs.get(carrierConfigKey);
1413             if (value == null) {
1414                 // Filter out keys without values.
1415                 // In history, many AOSP or OEMs/carriers private configs didn't provide default
1416                 // values. We have to continue supporting them for now. See b/261776046 for details.
1417                 continue;
1418             }
1419             // Config value itself could be PersistableBundle which requires different API to put
1420             if (value instanceof PersistableBundle) {
1421                 configSubset.putPersistableBundle(carrierConfigKey, (PersistableBundle) value);
1422             } else {
1423                 configSubset.putObject(carrierConfigKey, value);
1424             }
1425         }
1426 
1427         // Configs in CONFIG_SUBSET_ALWAYS_INCLUDED_KEYS should always be included
1428         for (String generalKey : CONFIG_SUBSET_METADATA_KEYS) {
1429             configSubset.putObject(generalKey, allConfigs.get(generalKey));
1430         }
1431 
1432         return configSubset;
1433     }
1434 
1435     @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_PHONE_STATE)
1436     @Override
overrideConfig(int subscriptionId, @Nullable PersistableBundle overrides, boolean persistent)1437     public void overrideConfig(int subscriptionId, @Nullable PersistableBundle overrides,
1438             boolean persistent) {
1439         overrideConfig_enforcePermission();
1440         int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
1441         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
1442             logd("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
1443             throw new IllegalArgumentException(
1444                     "Invalid phoneId " + phoneId + " for subId " + subscriptionId);
1445         }
1446 
1447         enforceTelephonyFeatureWithException(getCurrentPackageName(), "overrideConfig");
1448 
1449         // Post to run on handler thread on which all states should be confined.
1450         mHandler.post(() -> {
1451             overrideConfig(mOverrideConfigs, phoneId, overrides);
1452 
1453             if (persistent) {
1454                 overrideConfig(mPersistentOverrideConfigs, phoneId, overrides);
1455 
1456                 if (overrides != null) {
1457                     final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
1458                     saveConfigToXml(mPlatformCarrierConfigPackage, OVERRIDE_PACKAGE_ADDITION,
1459                             phoneId,
1460                             carrierId, mPersistentOverrideConfigs[phoneId]);
1461                 } else {
1462                     final String iccid = getIccIdForPhoneId(phoneId);
1463                     final int cid = getSpecificCarrierIdForPhoneId(phoneId);
1464                     String fileName = getFilenameForConfig(mPlatformCarrierConfigPackage,
1465                             OVERRIDE_PACKAGE_ADDITION, iccid, cid);
1466                     File fileToDelete = new File(mContext.getFilesDir(), fileName);
1467                     fileToDelete.delete();
1468                 }
1469             }
1470             logdWithLocalLog("overrideConfig: subId=" + subscriptionId + ", persistent="
1471                     + persistent + ", overrides=" + overrides);
1472             updateSubscriptionDatabase(phoneId);
1473         });
1474     }
1475 
overrideConfig(@onNull PersistableBundle[] currentOverrides, int phoneId, @Nullable PersistableBundle overrides)1476     private void overrideConfig(@NonNull PersistableBundle[] currentOverrides, int phoneId,
1477             @Nullable PersistableBundle overrides) {
1478         if (overrides == null) {
1479             currentOverrides[phoneId] = new PersistableBundle();
1480         } else if (currentOverrides[phoneId] == null) {
1481             currentOverrides[phoneId] = overrides;
1482         } else {
1483             currentOverrides[phoneId].putAll(overrides);
1484         }
1485     }
1486 
1487     @Override
notifyConfigChangedForSubId(int subscriptionId)1488     public void notifyConfigChangedForSubId(int subscriptionId) {
1489         // Requires the calling app to be either a carrier privileged app for this subId or
1490         // system privileged app with MODIFY_PHONE_STATE permission.
1491         TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mContext,
1492                 subscriptionId, "Require carrier privileges or MODIFY_PHONE_STATE permission.");
1493 
1494         int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
1495         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
1496             final String msg =
1497                     "Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId;
1498             if (mFeatureFlags.addAnomalyWhenNotifyConfigChangedWithInvalidPhone()) {
1499                 AnomalyReporter.reportAnomaly(
1500                         UUID.fromString(UUID_NOTIFY_CONFIG_CHANGED_WITH_INVALID_PHONE), msg);
1501             }
1502             logd(msg);
1503             throw new IllegalArgumentException(msg);
1504         }
1505 
1506         enforceTelephonyFeatureWithException(getCurrentPackageName(),
1507                 "notifyConfigChangedForSubId");
1508 
1509         logdWithLocalLog("Notified carrier config changed. phoneId=" + phoneId
1510                 + ", subId=" + subscriptionId);
1511 
1512         // This method should block until deleting has completed, so that an error which prevents us
1513         // from clearing the cache is passed back to the carrier app. With the files successfully
1514         // deleted, this can return and we will eventually bind to the carrier app.
1515         String callingPackageName = mContext.getPackageManager().getNameForUid(
1516                 Binder.getCallingUid());
1517         clearCachedConfigForPackage(callingPackageName);
1518         updateConfigForPhoneId(phoneId);
1519     }
1520 
1521     @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_PHONE_STATE)
1522     @Override
updateConfigForPhoneId(int phoneId, @NonNull String simState)1523     public void updateConfigForPhoneId(int phoneId, @NonNull String simState) {
1524         updateConfigForPhoneId_enforcePermission();
1525         logdWithLocalLog("Update config for phoneId=" + phoneId + " simState=" + simState);
1526         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
1527             throw new IllegalArgumentException("Invalid phoneId: " + phoneId);
1528         }
1529 
1530         enforceTelephonyFeatureWithException(getCurrentPackageName(), "updateConfigForPhoneId");
1531 
1532         // requires Java 7 for switch on string.
1533         switch (simState) {
1534             case IccCardConstants.INTENT_VALUE_ICC_ABSENT:
1535             case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR:
1536             case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED:
1537             case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN:
1538             case IccCardConstants.INTENT_VALUE_ICC_NOT_READY:
1539                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CLEAR_CONFIG, phoneId, -1));
1540                 break;
1541             case IccCardConstants.INTENT_VALUE_ICC_LOADED:
1542             case IccCardConstants.INTENT_VALUE_ICC_LOCKED:
1543                 updateConfigForPhoneId(phoneId);
1544                 break;
1545         }
1546     }
1547 
1548     @android.annotation.EnforcePermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
1549     @Override
1550     @NonNull
getDefaultCarrierServicePackageName()1551     public String getDefaultCarrierServicePackageName() {
1552         getDefaultCarrierServicePackageName_enforcePermission();
1553 
1554         enforceTelephonyFeatureWithException(getCurrentPackageName(),
1555                 "getDefaultCarrierServicePackageName");
1556 
1557         return mPlatformCarrierConfigPackage;
1558     }
1559 
1560     @VisibleForTesting
1561     @NonNull
getHandler()1562     /* package */ Handler getHandler() {
1563         return mHandler;
1564     }
1565 
1566     @VisibleForTesting
1567     @Nullable
getConfigFromDefaultApp(int phoneId)1568     /* package */ PersistableBundle getConfigFromDefaultApp(int phoneId) {
1569         return mConfigFromDefaultApp[phoneId];
1570     }
1571 
1572     @VisibleForTesting
1573     @Nullable
getConfigFromCarrierApp(int phoneId)1574     /* package */ PersistableBundle getConfigFromCarrierApp(int phoneId) {
1575         return mConfigFromCarrierApp[phoneId];
1576     }
1577 
1578     @VisibleForTesting
1579     @NonNull
getNoSimConfig()1580      /* package */ PersistableBundle getNoSimConfig() {
1581         return mNoSimConfig;
1582     }
1583 
1584     @VisibleForTesting
1585     @Nullable
getOverrideConfig(int phoneId)1586     /* package */ PersistableBundle getOverrideConfig(int phoneId) {
1587         return mOverrideConfigs[phoneId];
1588     }
1589 
1590     // TODO(b/185129900): always call unbindService after bind, no matter if it succeeded
unbindIfBound(@onNull Context context, @NonNull CarrierServiceConnection conn, int phoneId)1591     private void unbindIfBound(@NonNull Context context, @NonNull CarrierServiceConnection conn,
1592             int phoneId) {
1593         if (mServiceBound[phoneId]) {
1594             mServiceBound[phoneId] = false;
1595             context.unbindService(conn);
1596         }
1597     }
1598 
unbindIfBoundForNoSimConfig(@onNull Context context, @NonNull CarrierServiceConnection conn, int phoneId)1599     private void unbindIfBoundForNoSimConfig(@NonNull Context context,
1600             @NonNull CarrierServiceConnection conn, int phoneId) {
1601         if (mServiceBoundForNoSimConfig[phoneId]) {
1602             mServiceBoundForNoSimConfig[phoneId] = false;
1603             context.unbindService(conn);
1604         }
1605     }
1606 
1607     /**
1608      * Returns a boxed Integer object for phoneId, services as message token to distinguish messages
1609      * with same code when calling {@link Handler#removeMessages(int, Object)}.
1610      */
1611     @NonNull
getMessageToken(int phoneId)1612     private Integer getMessageToken(int phoneId) {
1613         if (phoneId < -128 || phoneId > 127) {
1614             throw new IllegalArgumentException("phoneId should be in range [-128, 127], inclusive");
1615         }
1616         // Integer#valueOf guarantees the integers within [-128, 127] are cached and thus memory
1617         // comparison (==) returns true for the same integer.
1618         return Integer.valueOf(phoneId);
1619     }
1620 
1621     /**
1622      * Get the file time in readable format.
1623      *
1624      * @param filePath The full file path.
1625      *
1626      * @return The time in string format.
1627      */
1628     @Nullable
getFileTime(@onNull String filePath)1629     private String getFileTime(@NonNull String filePath) {
1630         String formattedModifiedTime = null;
1631         try {
1632             // Convert the modified time to a readable format
1633             formattedModifiedTime = TIME_FORMAT.format(Files.readAttributes(Paths.get(filePath),
1634                     BasicFileAttributes.class).lastModifiedTime().toMillis());
1635         } catch (Exception e) {
1636             e.printStackTrace();
1637         }
1638 
1639         return formattedModifiedTime;
1640     }
1641 
1642     /**
1643      * If {@code args} contains {@link #DUMP_ARG_REQUESTING_PACKAGE} and a following package name,
1644      * we'll also call {@link IBinder#dump} on the default carrier service (if bound) and the
1645      * specified carrier service (if bound). Typically, this is done for connectivity bug reports
1646      * where we don't call {@code dumpsys activity service all-non-platform} because that contains
1647      * too much info, but we still want to let carrier apps include their diagnostics.
1648      */
1649     @Override
dump(@onNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args)1650     public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
1651         IndentingPrintWriter indentPW = new IndentingPrintWriter(pw, "    ");
1652         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1653                 != PackageManager.PERMISSION_GRANTED) {
1654             indentPW.println("Permission Denial: can't dump carrierconfig from from pid="
1655                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1656             return;
1657         }
1658         String requestingPackage = null;
1659         int requestingPackageIndex = ArrayUtils.indexOf(args, DUMP_ARG_REQUESTING_PACKAGE);
1660         if (requestingPackageIndex >= 0 && requestingPackageIndex < args.length - 1
1661                 && !TextUtils.isEmpty(args[requestingPackageIndex + 1])) {
1662             requestingPackage = args[requestingPackageIndex + 1];
1663             // Throws a SecurityException if the caller is impersonating another app in an effort to
1664             // dump extra info (which may contain PII the caller doesn't have a right to).
1665             enforceCallerIsSystemOrRequestingPackage(requestingPackage);
1666         }
1667 
1668         indentPW.println("CarrierConfigLoader: " + this);
1669         for (int i = 0; i < mNumPhones; i++) {
1670             indentPW.println("Phone Id = " + i);
1671             // display default values in CarrierConfigManager
1672             printConfig(CarrierConfigManager.getDefaultConfig(), indentPW,
1673                     "Default Values from CarrierConfigManager");
1674             // display ConfigFromDefaultApp
1675             printConfig(mConfigFromDefaultApp[i], indentPW, "mConfigFromDefaultApp");
1676             // display ConfigFromCarrierApp
1677             printConfig(mConfigFromCarrierApp[i], indentPW, "mConfigFromCarrierApp");
1678             printConfig(mPersistentOverrideConfigs[i], indentPW, "mPersistentOverrideConfigs");
1679             printConfig(mOverrideConfigs[i], indentPW, "mOverrideConfigs");
1680         }
1681 
1682         printConfig(mNoSimConfig, indentPW, "mNoSimConfig");
1683         indentPW.println("mNumPhones=" + mNumPhones);
1684         indentPW.println("mPlatformCarrierConfigPackage=" + mPlatformCarrierConfigPackage);
1685         indentPW.println("mServiceConnection=[" + Stream.of(mServiceConnection)
1686                 .map(c -> c != null ? c.pkgName : null)
1687                 .collect(Collectors.joining(", ")) + "]");
1688         indentPW.println("mServiceBoundForNoSimConfig="
1689                 + Arrays.toString(mServiceBoundForNoSimConfig));
1690         indentPW.println("mHasSentConfigChange=" + Arrays.toString(mHasSentConfigChange));
1691         indentPW.println("mFromSystemUnlocked=" + Arrays.toString(mFromSystemUnlocked));
1692         indentPW.println();
1693         indentPW.println("CarrierConfigLoader local log=");
1694         indentPW.increaseIndent();
1695         mCarrierConfigLoadingLog.dump(fd, indentPW, args);
1696         indentPW.decreaseIndent();
1697 
1698         if (requestingPackage != null) {
1699             logd("Including default and requesting package " + requestingPackage
1700                     + " carrier services in dump");
1701             indentPW.println("");
1702             indentPW.println("Connected services");
1703             dumpCarrierServiceIfBound(fd, indentPW, "Default config package",
1704                     mPlatformCarrierConfigPackage, false /* considerCarrierPrivileges */);
1705             dumpCarrierServiceIfBound(fd, indentPW, "Requesting package", requestingPackage,
1706                     true /* considerCarrierPrivileges */);
1707         }
1708 
1709         indentPW.println();
1710         indentPW.println("Cached config files:");
1711         indentPW.increaseIndent();
1712         for (File f : mContext.getFilesDir().listFiles((FilenameFilter) (d, filename)
1713                 -> filename.startsWith("carrierconfig-"))) {
1714             indentPW.println(getFilePathForLogging(f.getName()) + ", modified time="
1715                     + getFileTime(f.getAbsolutePath()));
1716         }
1717         indentPW.decreaseIndent();
1718     }
1719 
printConfig(@onNull PersistableBundle configApp, @NonNull IndentingPrintWriter indentPW, @NonNull String name)1720     private void printConfig(@NonNull PersistableBundle configApp,
1721             @NonNull IndentingPrintWriter indentPW, @NonNull String name) {
1722         indentPW.increaseIndent();
1723         if (configApp == null) {
1724             indentPW.println(name + " : null ");
1725             indentPW.decreaseIndent();
1726             indentPW.println("");
1727             return;
1728         }
1729         indentPW.println(name + " : ");
1730         List<String> sortedKeys = new ArrayList<String>(configApp.keySet());
1731         Collections.sort(sortedKeys);
1732         indentPW.increaseIndent();
1733         indentPW.increaseIndent();
1734         for (String key : sortedKeys) {
1735             if (configApp.get(key) != null && configApp.get(key) instanceof Object[]) {
1736                 indentPW.println(key + " = " +
1737                         Arrays.toString((Object[]) configApp.get(key)));
1738             } else if (configApp.get(key) != null && configApp.get(key) instanceof int[]) {
1739                 indentPW.println(key + " = " + Arrays.toString((int[]) configApp.get(key)));
1740             } else {
1741                 indentPW.println(key + " = " + configApp.get(key));
1742             }
1743         }
1744         indentPW.decreaseIndent();
1745         indentPW.decreaseIndent();
1746         indentPW.decreaseIndent();
1747         indentPW.println("");
1748     }
1749 
1750     /**
1751      * Passes without problem when one of these conditions is true:
1752      * - The caller is a privileged UID (e.g. for dumpstate.cpp generating a bug report, where the
1753      * system knows the true caller plumbed in through the {@link android.os.BugreportManager} API).
1754      * - The caller's UID matches the supplied package.
1755      *
1756      * @throws SecurityException if none of the above conditions are met.
1757      */
enforceCallerIsSystemOrRequestingPackage(@onNull String requestingPackage)1758     private void enforceCallerIsSystemOrRequestingPackage(@NonNull String requestingPackage)
1759             throws SecurityException {
1760         final int callingUid = Binder.getCallingUid();
1761         if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID
1762                 || callingUid == Process.SHELL_UID || callingUid == Process.PHONE_UID) {
1763             // Bug reports (dumpstate.cpp) run as SHELL, and let some other privileged UIDs through
1764             // as well.
1765             return;
1766         }
1767         // An app is trying to dump extra detail, block it if they aren't who they claim to be.
1768         AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
1769         if (appOps == null) {
1770             throw new SecurityException("No AppOps");
1771         }
1772         // Will throw a SecurityException if the UID and package don't match.
1773         appOps.checkPackage(callingUid, requestingPackage);
1774     }
1775 
1776     /**
1777      * Searches for one or more appropriate {@link CarrierService} instances to dump based on the
1778      * current connections.
1779      *
1780      * @param targetPkgName             the target package name to dump carrier services for
1781      * @param considerCarrierPrivileges if true, allow a carrier service to be dumped if it shares
1782      *                                  carrier privileges with {@code targetPkgName};
1783      *                                  otherwise, only dump a carrier service if it is {@code
1784      *                                  targetPkgName}
1785      */
dumpCarrierServiceIfBound(@onNull FileDescriptor fd, @NonNull IndentingPrintWriter indentPW, @NonNull String prefix, @NonNull String targetPkgName, boolean considerCarrierPrivileges)1786     private void dumpCarrierServiceIfBound(@NonNull FileDescriptor fd,
1787             @NonNull IndentingPrintWriter indentPW, @NonNull String prefix,
1788             @NonNull String targetPkgName, boolean considerCarrierPrivileges) {
1789         // Null package is possible if it's early in the boot process, there was a recent crash, we
1790         // loaded the config from XML most recently, or a SIM slot is empty. Carrier apps with
1791         // long-lived bindings should typically get dumped here regardless. Even if an app is being
1792         // used for multiple phoneIds, we assume that it's smart enough to handle that on its own,
1793         // and that in most cases we'd just be dumping duplicate information and bloating a report.
1794         indentPW.increaseIndent();
1795         indentPW.println(prefix + " : " + targetPkgName);
1796         Set<String> dumpedPkgNames = new ArraySet<>(mServiceConnection.length);
1797         for (CarrierServiceConnection connection : mServiceConnection) {
1798             if (connection == null || !SubscriptionManager.isValidPhoneId(connection.phoneId)
1799                     || TextUtils.isEmpty(connection.pkgName)) {
1800                 continue;
1801             }
1802             final String servicePkgName = connection.pkgName;
1803             // Note: we intentionally ignore system components here because we should NOT match the
1804             // shell caller that's typically used for bug reports via non-BugreportManager triggers.
1805             final boolean exactPackageMatch = TextUtils.equals(targetPkgName, servicePkgName);
1806             final boolean carrierPrivilegesMatch =
1807                     considerCarrierPrivileges && hasCarrierPrivileges(targetPkgName,
1808                             connection.phoneId);
1809             if (!exactPackageMatch && !carrierPrivilegesMatch) continue;
1810             // Make sure this service is actually alive before trying to dump it. We don't pay
1811             // attention to mServiceBound[connection.phoneId] because typically carrier apps will
1812             // request long-lived bindings, and even if we unbind the app, it may still be alive due
1813             // to CarrierServiceBindHelper. Pull it out as a reference so even if it gets set to
1814             // null within the ServiceConnection during unbinding we can avoid an NPE.
1815             final IBinder service = connection.service;
1816             if (service == null || !service.isBinderAlive() || !service.pingBinder()) continue;
1817             // We've got a live service. Last check is just to make sure we don't dump a package
1818             // multiple times.
1819             if (!dumpedPkgNames.add(servicePkgName)) continue;
1820             if (!exactPackageMatch) {
1821                 logd(targetPkgName + " has carrier privileges on phoneId " + connection.phoneId
1822                         + ", service provided by " + servicePkgName);
1823                 indentPW.increaseIndent();
1824                 indentPW.println("Proxy : " + servicePkgName);
1825                 indentPW.decreaseIndent();
1826             }
1827             // Flush before we let the app output anything to ensure correct ordering of output.
1828             // Internally, Binder#dump calls flush on its printer after finishing so we don't
1829             // need to do anything after.
1830             indentPW.flush();
1831             try {
1832                 logd("Dumping " + servicePkgName);
1833                 // We don't need to give the carrier service any args.
1834                 connection.service.dump(fd, null /* args */);
1835                 logd("Done with " + servicePkgName);
1836             } catch (RemoteException e) {
1837                 logd("RemoteException from " + servicePkgName, e);
1838                 indentPW.increaseIndent();
1839                 indentPW.println("RemoteException");
1840                 indentPW.increaseIndent();
1841                 e.printStackTrace(indentPW);
1842                 indentPW.decreaseIndent();
1843                 indentPW.decreaseIndent();
1844                 // We won't retry this package again because now it's in dumpedPkgNames.
1845             }
1846             indentPW.println("");
1847         }
1848         if (dumpedPkgNames.isEmpty()) {
1849             indentPW.increaseIndent();
1850             indentPW.println("Not bound");
1851             indentPW.decreaseIndent();
1852             indentPW.println("");
1853         }
1854         indentPW.decreaseIndent();
1855     }
1856 
hasCarrierPrivileges(@onNull String pkgName, int phoneId)1857     private boolean hasCarrierPrivileges(@NonNull String pkgName, int phoneId) {
1858         int subId = SubscriptionManager.getSubscriptionId(phoneId);
1859         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
1860             return false;
1861         }
1862         return TelephonyManager.from(mContext).createForSubscriptionId(subId)
1863                 .checkCarrierPrivilegesForPackage(pkgName)
1864                 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
1865     }
1866 
1867     /**
1868      * Get the current calling package name.
1869      * @return the current calling package name
1870      */
1871     @Nullable
getCurrentPackageName()1872     private String getCurrentPackageName() {
1873         if (mPackageManager == null) return null;
1874         String[] callingUids = mPackageManager.getPackagesForUid(Binder.getCallingUid());
1875         return (callingUids == null) ? null : callingUids[0];
1876     }
1877 
1878     /**
1879      * Make sure the device has required telephony feature
1880      *
1881      * @throws UnsupportedOperationException if the device does not have required telephony feature
1882      */
enforceTelephonyFeatureWithException(@ullable String callingPackage, @NonNull String methodName)1883     private void enforceTelephonyFeatureWithException(@Nullable String callingPackage,
1884             @NonNull String methodName) {
1885         if (callingPackage == null || mPackageManager == null) {
1886             return;
1887         }
1888 
1889         if (!mFeatureFlags.enforceTelephonyFeatureMappingForPublicApis()
1890                 || !CompatChanges.isChangeEnabled(ENABLE_FEATURE_MAPPING, callingPackage,
1891                 Binder.getCallingUserHandle())
1892                 || mVendorApiLevel < Build.VERSION_CODES.VANILLA_ICE_CREAM) {
1893             // Skip to check associated telephony feature,
1894             // if compatibility change is not enabled for the current process or
1895             // the SDK version of vendor partition is less than Android V.
1896             return;
1897         }
1898 
1899         if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY_SUBSCRIPTION)) {
1900             throw new UnsupportedOperationException(
1901                     methodName + " is unsupported without " + FEATURE_TELEPHONY_SUBSCRIPTION);
1902         }
1903     }
1904 
1905     private class CarrierServiceConnection implements ServiceConnection {
1906         final int phoneId;
1907         @NonNull final String pkgName;
1908         final int eventId;
1909         IBinder service;
1910 
CarrierServiceConnection(int phoneId, @NonNull String pkgName, int eventId)1911         CarrierServiceConnection(int phoneId, @NonNull String pkgName, int eventId) {
1912             this.phoneId = phoneId;
1913             this.pkgName = pkgName;
1914             this.eventId = eventId;
1915         }
1916 
1917         @Override
onServiceConnected(@onNull ComponentName name, @NonNull IBinder service)1918         public void onServiceConnected(@NonNull ComponentName name, @NonNull IBinder service) {
1919             logd("Connected to config app: " + name.flattenToShortString());
1920             this.service = service;
1921             mHandler.sendMessage(mHandler.obtainMessage(eventId, phoneId, -1, this));
1922         }
1923 
1924         @Override
onServiceDisconnected(@onNull ComponentName name)1925         public void onServiceDisconnected(@NonNull ComponentName name) {
1926             logd("Disconnected from config app: " + name.flattenToShortString());
1927             this.service = null;
1928         }
1929 
1930         @Override
onBindingDied(@onNull ComponentName name)1931         public void onBindingDied(@NonNull ComponentName name) {
1932             logd("Binding died from config app: " + name.flattenToShortString());
1933             this.service = null;
1934         }
1935 
1936         @Override
onNullBinding(@onNull ComponentName name)1937         public void onNullBinding(@NonNull ComponentName name) {
1938             logd("Null binding from config app: " + name.flattenToShortString());
1939             this.service = null;
1940         }
1941     }
1942 
1943     private class ConfigLoaderBroadcastReceiver extends BroadcastReceiver {
1944         @Override
onReceive(@onNull Context context, @NonNull Intent intent)1945         public void onReceive(@NonNull Context context, @NonNull Intent intent) {
1946             switch (intent.getAction()) {
1947                 case Intent.ACTION_BOOT_COMPLETED:
1948                     mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_UNLOCKED, null));
1949                     break;
1950             }
1951         }
1952     }
1953 
1954     private class CarrierServiceChangeCallback implements
1955             TelephonyManager.CarrierPrivilegesCallback {
1956         final int mPhoneId;
1957         // CarrierPrivilegesCallback will be triggered upon registration. Filter the first callback
1958         // here since we really care of the *change* of carrier service instead of the content
1959         private boolean mHasSentServiceChangeCallback;
1960 
CarrierServiceChangeCallback(int phoneId)1961         CarrierServiceChangeCallback(int phoneId) {
1962             this.mPhoneId = phoneId;
1963             this.mHasSentServiceChangeCallback = false;
1964         }
1965 
1966         @Override
onCarrierPrivilegesChanged( @ndroidx.annotation.NonNull Set<String> privilegedPackageNames, @androidx.annotation.NonNull Set<Integer> privilegedUids)1967         public void onCarrierPrivilegesChanged(
1968                 @androidx.annotation.NonNull Set<String> privilegedPackageNames,
1969                 @androidx.annotation.NonNull Set<Integer> privilegedUids) {
1970             // Ignored, not interested here
1971         }
1972 
1973         @Override
onCarrierServiceChanged( @ndroidx.annotation.Nullable String carrierServicePackageName, int carrierServiceUid)1974         public void onCarrierServiceChanged(
1975                 @androidx.annotation.Nullable String carrierServicePackageName,
1976                 int carrierServiceUid) {
1977             // Ignore the first callback which is triggered upon registration
1978             if (!mHasSentServiceChangeCallback) {
1979                 mHasSentServiceChangeCallback = true;
1980                 return;
1981             }
1982             mHandler.sendMessage(
1983                     mHandler.obtainMessage(EVENT_PACKAGE_CHANGED, mPhoneId, -1,
1984                             carrierServicePackageName));
1985         }
1986     }
1987 
1988     // Get readable string for the message code supported in this class.
1989     @NonNull
eventToString(int code)1990     private static String eventToString(int code) {
1991         switch (code) {
1992             case EVENT_CLEAR_CONFIG:
1993                 return "EVENT_CLEAR_CONFIG";
1994             case EVENT_CONNECTED_TO_DEFAULT:
1995                 return "EVENT_CONNECTED_TO_DEFAULT";
1996             case EVENT_CONNECTED_TO_CARRIER:
1997                 return "EVENT_CONNECTED_TO_CARRIER";
1998             case EVENT_FETCH_DEFAULT_DONE:
1999                 return "EVENT_FETCH_DEFAULT_DONE";
2000             case EVENT_FETCH_CARRIER_DONE:
2001                 return "EVENT_FETCH_CARRIER_DONE";
2002             case EVENT_DO_FETCH_DEFAULT:
2003                 return "EVENT_DO_FETCH_DEFAULT";
2004             case EVENT_DO_FETCH_CARRIER:
2005                 return "EVENT_DO_FETCH_CARRIER";
2006             case EVENT_PACKAGE_CHANGED:
2007                 return "EVENT_PACKAGE_CHANGED";
2008             case EVENT_BIND_DEFAULT_TIMEOUT:
2009                 return "EVENT_BIND_DEFAULT_TIMEOUT";
2010             case EVENT_BIND_CARRIER_TIMEOUT:
2011                 return "EVENT_BIND_CARRIER_TIMEOUT";
2012             case EVENT_CHECK_SYSTEM_UPDATE:
2013                 return "EVENT_CHECK_SYSTEM_UPDATE";
2014             case EVENT_SYSTEM_UNLOCKED:
2015                 return "EVENT_SYSTEM_UNLOCKED";
2016             case EVENT_FETCH_DEFAULT_TIMEOUT:
2017                 return "EVENT_FETCH_DEFAULT_TIMEOUT";
2018             case EVENT_FETCH_CARRIER_TIMEOUT:
2019                 return "EVENT_FETCH_CARRIER_TIMEOUT";
2020             case EVENT_SUBSCRIPTION_INFO_UPDATED:
2021                 return "EVENT_SUBSCRIPTION_INFO_UPDATED";
2022             case EVENT_MULTI_SIM_CONFIG_CHANGED:
2023                 return "EVENT_MULTI_SIM_CONFIG_CHANGED";
2024             case EVENT_DO_FETCH_DEFAULT_FOR_NO_SIM_CONFIG:
2025                 return "EVENT_DO_FETCH_DEFAULT_FOR_NO_SIM_CONFIG";
2026             case EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE:
2027                 return "EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_DONE";
2028             case EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG:
2029                 return "EVENT_CONNECTED_TO_DEFAULT_FOR_NO_SIM_CONFIG";
2030             case EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT:
2031                 return "EVENT_BIND_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT";
2032             case EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT:
2033                 return "EVENT_FETCH_DEFAULT_FOR_NO_SIM_CONFIG_TIMEOUT";
2034             default:
2035                 return "UNKNOWN(" + code + ")";
2036         }
2037     }
2038 
logd(@onNull String msg)2039     private void logd(@NonNull String msg) {
2040         Log.d(LOG_TAG, msg);
2041     }
2042 
logd(@onNull String msg, Throwable tr)2043     private void logd(@NonNull String msg, Throwable tr) {
2044         Log.d(LOG_TAG, msg, tr);
2045     }
2046 
logdWithLocalLog(@onNull String msg)2047     private void logdWithLocalLog(@NonNull String msg) {
2048         Log.d(LOG_TAG, msg);
2049         mCarrierConfigLoadingLog.log(msg);
2050     }
2051 
loge(@onNull String msg)2052     private void loge(@NonNull String msg) {
2053         Log.e(LOG_TAG, msg);
2054         mCarrierConfigLoadingLog.log(msg);
2055     }
2056 }
2057