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