• 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.Manifest.permission.READ_PHONE_STATE;
20 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
21 import static android.service.carrier.CarrierService.ICarrierServiceWrapper.KEY_CONFIG_BUNDLE;
22 import static android.service.carrier.CarrierService.ICarrierServiceWrapper.RESULT_ERROR;
23 
24 import android.annotation.NonNull;
25 import android.app.ActivityManager;
26 import android.content.BroadcastReceiver;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.IntentFilter;
31 import android.content.ServiceConnection;
32 import android.content.SharedPreferences;
33 import android.content.pm.PackageInfo;
34 import android.content.pm.PackageManager;
35 import android.os.Binder;
36 import android.os.Build;
37 import android.os.Bundle;
38 import android.os.Handler;
39 import android.os.IBinder;
40 import android.os.Message;
41 import android.os.PersistableBundle;
42 import android.os.RemoteException;
43 import android.os.ResultReceiver;
44 import android.os.ServiceManager;
45 import android.os.UserHandle;
46 import android.preference.PreferenceManager;
47 import android.service.carrier.CarrierIdentifier;
48 import android.service.carrier.CarrierService;
49 import android.service.carrier.ICarrierService;
50 import android.telephony.CarrierConfigManager;
51 import android.telephony.SubscriptionManager;
52 import android.telephony.TelephonyManager;
53 import android.util.Log;
54 
55 import com.android.internal.telephony.ICarrierConfigLoader;
56 import com.android.internal.telephony.IccCardConstants;
57 import com.android.internal.telephony.Phone;
58 import com.android.internal.telephony.PhoneFactory;
59 import com.android.internal.telephony.TelephonyPermissions;
60 import com.android.internal.util.FastXmlSerializer;
61 import com.android.internal.util.IndentingPrintWriter;
62 
63 import org.xmlpull.v1.XmlPullParser;
64 import org.xmlpull.v1.XmlPullParserException;
65 import org.xmlpull.v1.XmlPullParserFactory;
66 
67 import java.io.File;
68 import java.io.FileDescriptor;
69 import java.io.FileInputStream;
70 import java.io.FileNotFoundException;
71 import java.io.FileOutputStream;
72 import java.io.FilenameFilter;
73 import java.io.IOException;
74 import java.io.PrintWriter;
75 import java.util.ArrayList;
76 import java.util.Arrays;
77 import java.util.Collections;
78 import java.util.List;
79 
80 /**
81  * CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays.
82  */
83 
84 public class CarrierConfigLoader extends ICarrierConfigLoader.Stub {
85     private static final String LOG_TAG = "CarrierConfigLoader";
86 
87     // Package name for platform carrier config app, bundled with system image.
88     private final String mPlatformCarrierConfigPackage;
89 
90     /** The singleton instance. */
91     private static CarrierConfigLoader sInstance;
92     // The context for phone app, passed from PhoneGlobals.
93     private Context mContext;
94     // Carrier configs from default app, indexed by phoneID.
95     private PersistableBundle[] mConfigFromDefaultApp;
96     // Carrier configs from privileged carrier config app, indexed by phoneID.
97     private PersistableBundle[] mConfigFromCarrierApp;
98     // Service connection for binding to config app.
99     private CarrierServiceConnection[] mServiceConnection;
100     // Whether we have sent config change bcast for each phone id.
101     private boolean[] mHasSentConfigChange;
102 
103     // Broadcast receiver for Boot intents, register intent filter in construtor.
104     private final BroadcastReceiver mBootReceiver = new ConfigLoaderBroadcastReceiver();
105     // Broadcast receiver for SIM and pkg intents, register intent filter in constructor.
106     private final BroadcastReceiver mPackageReceiver = new ConfigLoaderBroadcastReceiver();
107 
108     // Message codes; see mHandler below.
109     // Request from SubscriptionInfoUpdater when SIM becomes absent or error.
110     private static final int EVENT_CLEAR_CONFIG = 0;
111     // Has connected to default app.
112     private static final int EVENT_CONNECTED_TO_DEFAULT = 3;
113     // Has connected to carrier app.
114     private static final int EVENT_CONNECTED_TO_CARRIER = 4;
115     // Config has been loaded from default app (or cache).
116     private static final int EVENT_FETCH_DEFAULT_DONE = 5;
117     // Config has been loaded from carrier app (or cache).
118     private static final int EVENT_FETCH_CARRIER_DONE = 6;
119     // Attempt to fetch from default app or read from XML.
120     private static final int EVENT_DO_FETCH_DEFAULT = 7;
121     // Attempt to fetch from carrier app or read from XML.
122     private static final int EVENT_DO_FETCH_CARRIER = 8;
123     // A package has been installed, uninstalled, or updated.
124     private static final int EVENT_PACKAGE_CHANGED = 9;
125     // Bind timed out for the default app.
126     private static final int EVENT_BIND_DEFAULT_TIMEOUT = 10;
127     // Bind timed out for a carrier app.
128     private static final int EVENT_BIND_CARRIER_TIMEOUT = 11;
129     // Check if the system fingerprint has changed.
130     private static final int EVENT_CHECK_SYSTEM_UPDATE = 12;
131     // Rerun carrier config binding after system is unlocked.
132     private static final int EVENT_SYSTEM_UNLOCKED = 13;
133     // Fetching config timed out from the default app.
134     private static final int EVENT_FETCH_DEFAULT_TIMEOUT = 14;
135     // Fetching config timed out from a carrier app.
136     private static final int EVENT_FETCH_CARRIER_TIMEOUT = 15;
137 
138     private static final int BIND_TIMEOUT_MILLIS = 30000;
139 
140     // Tags used for saving and restoring XML documents.
141     private static final String TAG_DOCUMENT = "carrier_config";
142     private static final String TAG_VERSION = "package_version";
143     private static final String TAG_BUNDLE = "bundle_data";
144 
145     // SharedPreferences key for last known build fingerprint.
146     private static final String KEY_FINGERPRINT = "build_fingerprint";
147 
148     // Handler to process various events.
149     //
150     // For each phoneId, the event sequence should be:
151     //     fetch default, connected to default, fetch default (async), fetch default done,
152     //     fetch carrier, connected to carrier, fetch carrier (async), fetch carrier done.
153     //
154     // If there is a saved config file for either the default app or the carrier app, we skip
155     // binding to the app and go straight from fetch to loaded.
156     //
157     // At any time, at most one connection is active. If events are not in this order, previous
158     // connection will be unbound, so only latest event takes effect.
159     //
160     // We broadcast ACTION_CARRIER_CONFIG_CHANGED after:
161     // 1. loading from carrier app (even if read from a file)
162     // 2. loading from default app if there is no carrier app (even if read from a file)
163     // 3. clearing config (e.g. due to sim removal)
164     // 4. encountering bind or IPC error
165     private class ConfigHandler extends Handler {
166         @Override
handleMessage(Message msg)167         public void handleMessage(Message msg) {
168             final int phoneId = msg.arg1;
169             log("mHandler: " + msg.what + " phoneId: " + phoneId);
170             switch (msg.what) {
171                 case EVENT_CLEAR_CONFIG:
172                 {
173                     /* Ignore clear configuration request if device is being shutdown. */
174                     Phone phone = PhoneFactory.getPhone(phoneId);
175                     if (phone != null) {
176                         if (phone.isShuttingDown()) {
177                             break;
178                         }
179                     }
180 
181                     if (mConfigFromDefaultApp[phoneId] == null
182                             && mConfigFromCarrierApp[phoneId] == null) break;
183 
184                     mConfigFromDefaultApp[phoneId] = null;
185                     mConfigFromCarrierApp[phoneId] = null;
186                     mServiceConnection[phoneId] = null;
187                     broadcastConfigChangedIntent(phoneId, false);
188                     break;
189                 }
190 
191                 case EVENT_SYSTEM_UNLOCKED:
192                 {
193                     for (int i = 0; i < TelephonyManager.from(mContext).getPhoneCount(); ++i) {
194                         // When user unlock device, we should only try to send broadcast again if we
195                         // have sent it before unlock. This will avoid we try to load carrier config
196                         // when SIM is still loading when unlock happens.
197                         if (mHasSentConfigChange[i]) {
198                             updateConfigForPhoneId(i);
199                         }
200                     }
201                     break;
202                 }
203 
204                 case EVENT_PACKAGE_CHANGED:
205                 {
206                     final String carrierPackageName = (String) msg.obj;
207                     // Only update if there are cached config removed to avoid updating config for
208                     // unrelated packages.
209                     if (clearCachedConfigForPackage(carrierPackageName)) {
210                         int numPhones = TelephonyManager.from(mContext).getPhoneCount();
211                         for (int i = 0; i < numPhones; ++i) {
212                             updateConfigForPhoneId(i);
213                         }
214                     }
215                     break;
216                 }
217 
218                 case EVENT_DO_FETCH_DEFAULT:
219                 {
220                     final String iccid = getIccIdForPhoneId(phoneId);
221                     final PersistableBundle config =
222                             restoreConfigFromXml(mPlatformCarrierConfigPackage, iccid);
223                     if (config != null) {
224                         log(
225                                 "Loaded config from XML. package="
226                                         + mPlatformCarrierConfigPackage
227                                         + " phoneId="
228                                         + phoneId);
229                         mConfigFromDefaultApp[phoneId] = config;
230                         Message newMsg = obtainMessage(EVENT_FETCH_DEFAULT_DONE, phoneId, -1);
231                         newMsg.getData().putBoolean("loaded_from_xml", true);
232                         mHandler.sendMessage(newMsg);
233                     } else {
234                         // No cached config, so fetch it from the default app.
235                         if (bindToConfigPackage(
236                                 mPlatformCarrierConfigPackage,
237                                 phoneId,
238                                 EVENT_CONNECTED_TO_DEFAULT)) {
239                             sendMessageDelayed(
240                                     obtainMessage(EVENT_BIND_DEFAULT_TIMEOUT, phoneId, -1),
241                                     BIND_TIMEOUT_MILLIS);
242                         } else {
243                             // Send broadcast if bind fails.
244                             broadcastConfigChangedIntent(phoneId);
245                             // TODO: We *must* call unbindService even if bindService returns false.
246                             // (And possibly if SecurityException was thrown.)
247                         }
248                     }
249                     break;
250                 }
251 
252                 case EVENT_CONNECTED_TO_DEFAULT:
253                 {
254                     removeMessages(EVENT_BIND_DEFAULT_TIMEOUT);
255                     final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
256                     // If new service connection has been created, unbind.
257                     if (mServiceConnection[phoneId] != conn || conn.service == null) {
258                         mContext.unbindService(conn);
259                         break;
260                     }
261                     final CarrierIdentifier carrierId = getCarrierIdForPhoneId(phoneId);
262                     final String iccid = getIccIdForPhoneId(phoneId);
263                     // ResultReceiver callback will execute in this Handler's thread.
264                     final ResultReceiver resultReceiver =
265                             new ResultReceiver(this) {
266                                 @Override
267                                 public void onReceiveResult(int resultCode, Bundle resultData) {
268                                     mContext.unbindService(conn);
269                                     // If new service connection has been created, this is stale.
270                                     if (mServiceConnection[phoneId] != conn) {
271                                         loge("Received response for stale request.");
272                                         return;
273                                     }
274                                     removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT);
275                                     if (resultCode == RESULT_ERROR || resultData == null) {
276                                         // On error, abort config fetching.
277                                         loge("Failed to get carrier config");
278                                         broadcastConfigChangedIntent(phoneId);
279                                         return;
280                                     }
281                                     PersistableBundle config =
282                                             resultData.getParcelable(KEY_CONFIG_BUNDLE);
283                                     saveConfigToXml(
284                                             mPlatformCarrierConfigPackage, iccid, config);
285                                     mConfigFromDefaultApp[phoneId] = config;
286                                     sendMessage(
287                                             obtainMessage(
288                                                     EVENT_FETCH_DEFAULT_DONE, phoneId, -1));
289                                 }
290                             };
291                     // Now fetch the config asynchronously from the ICarrierService.
292                     try {
293                         ICarrierService carrierService =
294                                 ICarrierService.Stub.asInterface(conn.service);
295                         carrierService.getCarrierConfig(carrierId, resultReceiver);
296                     } catch (RemoteException e) {
297                         loge("Failed to get carrier config: " + e.toString());
298                         mContext.unbindService(conn);
299                         break; // So we don't set a timeout.
300                     }
301                     sendMessageDelayed(
302                             obtainMessage(EVENT_FETCH_DEFAULT_TIMEOUT, phoneId, -1),
303                             BIND_TIMEOUT_MILLIS);
304                     break;
305                 }
306 
307                 case EVENT_BIND_DEFAULT_TIMEOUT:
308                 case EVENT_FETCH_DEFAULT_TIMEOUT:
309                 {
310                     // If a ResponseReceiver callback is in the queue when this happens, we will
311                     // unbind twice and throw an exception.
312                     mContext.unbindService(mServiceConnection[phoneId]);
313                     removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT);
314                     broadcastConfigChangedIntent(phoneId);
315                     break;
316                 }
317 
318                 case EVENT_FETCH_DEFAULT_DONE:
319                 {
320                     // If we attempted to bind to the app, but the service connection is null, then
321                     // config was cleared while we were waiting and we should not continue.
322                     if (!msg.getData().getBoolean("loaded_from_xml", false)
323                             && mServiceConnection[phoneId] == null) {
324                         break;
325                     }
326                     final String carrierPackageName = getCarrierPackageForPhoneId(phoneId);
327                     if (carrierPackageName != null) {
328                         log("Found carrier config app: " + carrierPackageName);
329                         sendMessage(obtainMessage(EVENT_DO_FETCH_CARRIER, phoneId));
330                     } else {
331                         broadcastConfigChangedIntent(phoneId);
332                     }
333                     break;
334                 }
335 
336                 case EVENT_DO_FETCH_CARRIER:
337                 {
338                     final String carrierPackageName = getCarrierPackageForPhoneId(phoneId);
339                     final String iccid = getIccIdForPhoneId(phoneId);
340                     final PersistableBundle config =
341                             restoreConfigFromXml(carrierPackageName, iccid);
342                     if (config != null) {
343                         log(
344                                 "Loaded config from XML. package="
345                                         + carrierPackageName
346                                         + " phoneId="
347                                         + phoneId);
348                         mConfigFromCarrierApp[phoneId] = config;
349                         Message newMsg = obtainMessage(EVENT_FETCH_CARRIER_DONE, phoneId, -1);
350                         newMsg.getData().putBoolean("loaded_from_xml", true);
351                         sendMessage(newMsg);
352                     } else {
353                         // No cached config, so fetch it from a carrier app.
354                         if (carrierPackageName != null
355                                 && bindToConfigPackage(
356                                         carrierPackageName,
357                                         phoneId,
358                                         EVENT_CONNECTED_TO_CARRIER)) {
359                             sendMessageDelayed(
360                                     obtainMessage(EVENT_BIND_CARRIER_TIMEOUT, phoneId, -1),
361                                     BIND_TIMEOUT_MILLIS);
362                         } else {
363                             // Send broadcast if bind fails.
364                             broadcastConfigChangedIntent(phoneId);
365                         }
366                     }
367                     break;
368                 }
369 
370                 case EVENT_CONNECTED_TO_CARRIER:
371                 {
372                     removeMessages(EVENT_BIND_CARRIER_TIMEOUT);
373                     final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
374                     // If new service connection has been created, unbind.
375                     if (mServiceConnection[phoneId] != conn || conn.service == null) {
376                         mContext.unbindService(conn);
377                         break;
378                     }
379                     final CarrierIdentifier carrierId = getCarrierIdForPhoneId(phoneId);
380                     final String iccid = getIccIdForPhoneId(phoneId);
381                     // ResultReceiver callback will execute in this Handler's thread.
382                     final ResultReceiver resultReceiver =
383                             new ResultReceiver(this) {
384                                 @Override
385                                 public void onReceiveResult(int resultCode, Bundle resultData) {
386                                     mContext.unbindService(conn);
387                                     // If new service connection has been created, this is stale.
388                                     if (mServiceConnection[phoneId] != conn) {
389                                         loge("Received response for stale request.");
390                                         return;
391                                     }
392                                     removeMessages(EVENT_FETCH_CARRIER_TIMEOUT);
393                                     if (resultCode == RESULT_ERROR || resultData == null) {
394                                         // On error, abort config fetching.
395                                         loge("Failed to get carrier config");
396                                         broadcastConfigChangedIntent(phoneId);
397                                         return;
398                                     }
399                                     PersistableBundle config =
400                                             resultData.getParcelable(KEY_CONFIG_BUNDLE);
401                                     saveConfigToXml(
402                                             getCarrierPackageForPhoneId(phoneId), iccid, config);
403                                     mConfigFromCarrierApp[phoneId] = config;
404                                     sendMessage(
405                                             obtainMessage(
406                                                     EVENT_FETCH_CARRIER_DONE, phoneId, -1));
407                                 }
408                             };
409                     // Now fetch the config asynchronously from the ICarrierService.
410                     try {
411                         ICarrierService carrierService =
412                                 ICarrierService.Stub.asInterface(conn.service);
413                         carrierService.getCarrierConfig(carrierId, resultReceiver);
414                     } catch (RemoteException e) {
415                         loge("Failed to get carrier config: " + e.toString());
416                         mContext.unbindService(conn);
417                         break; // So we don't set a timeout.
418                     }
419                     sendMessageDelayed(
420                             obtainMessage(EVENT_FETCH_CARRIER_TIMEOUT, phoneId, -1),
421                             BIND_TIMEOUT_MILLIS);
422                     break;
423                 }
424 
425                 case EVENT_BIND_CARRIER_TIMEOUT:
426                 case EVENT_FETCH_CARRIER_TIMEOUT:
427                 {
428                     // If a ResponseReceiver callback is in the queue when this happens, we will
429                     // unbind twice and throw an exception.
430                     mContext.unbindService(mServiceConnection[phoneId]);
431                     removeMessages(EVENT_FETCH_CARRIER_TIMEOUT);
432                     broadcastConfigChangedIntent(phoneId);
433                     break;
434                 }
435 
436                 case EVENT_FETCH_CARRIER_DONE:
437                 {
438                     // If we attempted to bind to the app, but the service connection is null, then
439                     // config was cleared while we were waiting and we should not continue.
440                     if (!msg.getData().getBoolean("loaded_from_xml", false)
441                             && mServiceConnection[phoneId] == null) {
442                         break;
443                     }
444                     broadcastConfigChangedIntent(phoneId);
445                     break;
446                 }
447 
448                 case EVENT_CHECK_SYSTEM_UPDATE:
449                 {
450                     SharedPreferences sharedPrefs =
451                             PreferenceManager.getDefaultSharedPreferences(mContext);
452                     final String lastFingerprint = sharedPrefs.getString(KEY_FINGERPRINT, null);
453                     if (!Build.FINGERPRINT.equals(lastFingerprint)) {
454                         log(
455                                 "Build fingerprint changed. old: "
456                                         + lastFingerprint
457                                         + " new: "
458                                         + Build.FINGERPRINT);
459                         clearCachedConfigForPackage(null);
460                         sharedPrefs
461                                 .edit()
462                                 .putString(KEY_FINGERPRINT, Build.FINGERPRINT)
463                                 .apply();
464                     }
465                     break;
466                 }
467             }
468         }
469     }
470 
471     private final Handler mHandler;
472 
473     /**
474      * Constructs a CarrierConfigLoader, registers it as a service, and registers a broadcast
475      * receiver for relevant events.
476      */
CarrierConfigLoader(Context context)477     private CarrierConfigLoader(Context context) {
478         mContext = context;
479         mPlatformCarrierConfigPackage =
480                 mContext.getString(R.string.platform_carrier_config_package);
481         mHandler = new ConfigHandler();
482 
483         IntentFilter bootFilter = new IntentFilter();
484         bootFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
485         context.registerReceiver(mBootReceiver, bootFilter);
486 
487         // Register for package updates. Update app or uninstall app update will have all 3 intents,
488         // in the order or removed, added, replaced, all with extra_replace set to true.
489         IntentFilter pkgFilter = new IntentFilter();
490         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
491         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
492         pkgFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
493         pkgFilter.addDataScheme("package");
494         context.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, pkgFilter, null, null);
495 
496         int numPhones = TelephonyManager.from(context).getPhoneCount();
497         mConfigFromDefaultApp = new PersistableBundle[numPhones];
498         mConfigFromCarrierApp = new PersistableBundle[numPhones];
499         mServiceConnection = new CarrierServiceConnection[numPhones];
500         mHasSentConfigChange = new boolean[numPhones];
501         // Make this service available through ServiceManager.
502         ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this);
503         log("CarrierConfigLoader has started");
504         mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE);
505     }
506 
507     /**
508      * Initialize the singleton CarrierConfigLoader instance.
509      *
510      * This is only done once, at startup, from {@link com.android.phone.PhoneApp#onCreate}.
511      */
512     /* package */
init(Context context)513     static CarrierConfigLoader init(Context context) {
514         synchronized (CarrierConfigLoader.class) {
515             if (sInstance == null) {
516                 sInstance = new CarrierConfigLoader(context);
517             } else {
518                 Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
519             }
520             return sInstance;
521         }
522     }
523 
broadcastConfigChangedIntent(int phoneId)524     private void broadcastConfigChangedIntent(int phoneId) {
525         broadcastConfigChangedIntent(phoneId, true);
526     }
527 
broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra)528     private void broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra) {
529         Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
530         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
531                 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
532         // Include subId extra only if SIM records are loaded
533         TelephonyManager telephonyManager = TelephonyManager.from(mContext);
534         int simApplicationState = telephonyManager.getSimApplicationState();
535         if (addSubIdExtra && (simApplicationState != TelephonyManager.SIM_STATE_UNKNOWN
536                 && simApplicationState != TelephonyManager.SIM_STATE_NOT_READY)) {
537             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
538         }
539         intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, phoneId);
540         ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
541         mHasSentConfigChange[phoneId] = true;
542     }
543 
544     /** Binds to the default or carrier config app. */
bindToConfigPackage(String pkgName, int phoneId, int eventId)545     private boolean bindToConfigPackage(String pkgName, int phoneId, int eventId) {
546         log("Binding to " + pkgName + " for phone " + phoneId);
547         Intent carrierService = new Intent(CarrierService.CARRIER_SERVICE_INTERFACE);
548         carrierService.setPackage(pkgName);
549         mServiceConnection[phoneId] = new CarrierServiceConnection(phoneId, eventId);
550         try {
551             return mContext.bindService(carrierService, mServiceConnection[phoneId],
552                     Context.BIND_AUTO_CREATE);
553         } catch (SecurityException ex) {
554             return false;
555         }
556     }
557 
getCarrierIdForPhoneId(int phoneId)558     private CarrierIdentifier getCarrierIdForPhoneId(int phoneId) {
559         String mcc = "";
560         String mnc = "";
561         String imsi = "";
562         String gid1 = "";
563         String gid2 = "";
564         String spn = TelephonyManager.from(mContext).getSimOperatorNameForPhone(phoneId);
565         String simOperator = TelephonyManager.from(mContext).getSimOperatorNumericForPhone(phoneId);
566         // A valid simOperator should be 5 or 6 digits, depending on the length of the MNC.
567         if (simOperator != null && simOperator.length() >= 3) {
568             mcc = simOperator.substring(0, 3);
569             mnc = simOperator.substring(3);
570         }
571         Phone phone = PhoneFactory.getPhone(phoneId);
572         if (phone != null) {
573             imsi = phone.getSubscriberId();
574             gid1 = phone.getGroupIdLevel1();
575             gid2 = phone.getGroupIdLevel2();
576         }
577 
578         return new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2);
579     }
580 
581     /** Returns the package name of a priveleged carrier app, or null if there is none. */
getCarrierPackageForPhoneId(int phoneId)582     private String getCarrierPackageForPhoneId(int phoneId) {
583         List<String> carrierPackageNames = TelephonyManager.from(mContext)
584                 .getCarrierPackageNamesForIntentAndPhone(
585                         new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), phoneId);
586         if (carrierPackageNames != null && carrierPackageNames.size() > 0) {
587             return carrierPackageNames.get(0);
588         } else {
589             return null;
590         }
591     }
592 
getIccIdForPhoneId(int phoneId)593     private String getIccIdForPhoneId(int phoneId) {
594         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
595             return null;
596         }
597         Phone phone = PhoneFactory.getPhone(phoneId);
598         if (phone == null) {
599             return null;
600         }
601         return phone.getIccSerialNumber();
602     }
603 
604     /**
605      * Writes a bundle to an XML file.
606      *
607      * The bundle will be written to a file named after the package name and ICCID, so that it can
608      * be restored later with {@link @restoreConfigFromXml}. The XML output will include the bundle
609      * and the current version of the specified package.
610      *
611      * In case of errors or invalid input, no file will be written.
612      *
613      * @param packageName the name of the package from which we fetched this bundle.
614      * @param iccid the ICCID of the subscription for which this bundle was fetched.
615      * @param config the bundle to be written. Null will be treated as an empty bundle.
616      */
saveConfigToXml(String packageName, String iccid, PersistableBundle config)617     private void saveConfigToXml(String packageName, String iccid, PersistableBundle config) {
618         if (packageName == null || iccid == null) {
619             loge("Cannot save config with null packageName or iccid.");
620             return;
621         }
622         // b/32668103 Only save to file if config isn't empty.
623         // In case of failure, not caching an empty bundle will
624         // try loading config again on next power on or sim loaded.
625         // Downside is for genuinely empty bundle, will bind and load
626         // on every power on.
627         if (config == null || config.isEmpty()) {
628             return;
629         }
630 
631         final String version = getPackageVersion(packageName);
632         if (version == null) {
633             loge("Failed to get package version for: " + packageName);
634             return;
635         }
636 
637         FileOutputStream outFile = null;
638         try {
639             outFile = new FileOutputStream(
640                     new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid)));
641             FastXmlSerializer out = new FastXmlSerializer();
642             out.setOutput(outFile, "utf-8");
643             out.startDocument("utf-8", true);
644             out.startTag(null, TAG_DOCUMENT);
645             out.startTag(null, TAG_VERSION);
646             out.text(version);
647             out.endTag(null, TAG_VERSION);
648             out.startTag(null, TAG_BUNDLE);
649             config.saveToXml(out);
650             out.endTag(null, TAG_BUNDLE);
651             out.endTag(null, TAG_DOCUMENT);
652             out.endDocument();
653             out.flush();
654             outFile.close();
655         }
656         catch (IOException e) {
657             loge(e.toString());
658         }
659         catch (XmlPullParserException e) {
660             loge(e.toString());
661         }
662     }
663 
664     /**
665      * Reads a bundle from an XML file.
666      *
667      * This restores a bundle that was written with {@link #saveConfigToXml}. This returns the saved
668      * config bundle for the given package and ICCID.
669      *
670      * In case of errors, or if the saved config is from a different package version than the
671      * current version, then null will be returned.
672      *
673      * @param packageName the name of the package from which we fetched this bundle.
674      * @param iccid the ICCID of the subscription for which this bundle was fetched.
675      * @return the bundle from the XML file. Returns null if there is no saved config, the saved
676      *         version does not match, or reading config fails.
677      */
restoreConfigFromXml(String packageName, String iccid)678     private PersistableBundle restoreConfigFromXml(String packageName, String iccid) {
679         final String version = getPackageVersion(packageName);
680         if (version == null) {
681             loge("Failed to get package version for: " + packageName);
682             return null;
683         }
684         if (packageName == null || iccid == null) {
685             loge("Cannot restore config with null packageName or iccid.");
686             return null;
687         }
688 
689         PersistableBundle restoredBundle = null;
690         FileInputStream inFile = null;
691         try {
692             inFile = new FileInputStream(
693                     new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid)));
694             XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
695             parser.setInput(inFile, "utf-8");
696 
697             int event;
698             while (((event = parser.next()) != XmlPullParser.END_DOCUMENT)) {
699 
700                 if (event == XmlPullParser.START_TAG && TAG_VERSION.equals(parser.getName())) {
701                     String savedVersion = parser.nextText();
702                     if (!version.equals(savedVersion)) {
703                         log("Saved version mismatch: " + version + " vs " + savedVersion);
704                         break;
705                     }
706                 }
707 
708                 if (event == XmlPullParser.START_TAG && TAG_BUNDLE.equals(parser.getName())) {
709                     restoredBundle = PersistableBundle.restoreFromXml(parser);
710                 }
711             }
712             inFile.close();
713         }
714         catch (FileNotFoundException e) {
715             loge(e.toString());
716         }
717         catch (XmlPullParserException e) {
718             loge(e.toString());
719         }
720         catch (IOException e) {
721             loge(e.toString());
722         }
723 
724         return restoredBundle;
725     }
726 
727     /**
728      * Clears cached carrier config.
729      * This deletes all saved XML files associated with the given package name. If packageName is
730      * null, then it deletes all saved XML files.
731      *
732      * @param packageName the name of a carrier package, or null if all cached config should be
733      *                    cleared.
734      * @return true iff one or more files were deleted.
735      */
clearCachedConfigForPackage(final String packageName)736     private boolean clearCachedConfigForPackage(final String packageName) {
737         File dir = mContext.getFilesDir();
738         File[] packageFiles = dir.listFiles(new FilenameFilter() {
739             public boolean accept(File dir, String filename) {
740                 if (packageName != null) {
741                     return filename.startsWith("carrierconfig-" + packageName + "-");
742                 } else {
743                     return filename.startsWith("carrierconfig-");
744                 }
745             }
746         });
747         if (packageFiles == null || packageFiles.length < 1) return false;
748         for (File f : packageFiles) {
749             log("deleting " + f.getName());
750             f.delete();
751         }
752         return true;
753     }
754 
755     /** Builds a canonical file name for a config file. */
getFilenameForConfig(@onNull String packageName, @NonNull String iccid)756     private String getFilenameForConfig(@NonNull String packageName, @NonNull String iccid) {
757         return "carrierconfig-" + packageName + "-" + iccid + ".xml";
758     }
759 
760     /** Return the current version code of a package, or null if the name is not found. */
getPackageVersion(String packageName)761     private String getPackageVersion(String packageName) {
762         try {
763             PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
764             return Long.toString(info.getLongVersionCode());
765         } catch (PackageManager.NameNotFoundException e) {
766             return null;
767         }
768     }
769 
770     /**
771      * Read up to date config.
772      *
773      * This reads config bundles for the given phoneId. That means getting the latest bundle from
774      * the default app and a privileged carrier app, if present. This will not bind to an app if we
775      * have a saved config file to use instead.
776      */
updateConfigForPhoneId(int phoneId)777     private void updateConfigForPhoneId(int phoneId) {
778         // Clear in-memory cache for carrier app config, so when carrier app gets uninstalled, no
779         // stale config is left.
780         if (mConfigFromCarrierApp[phoneId] != null &&
781                 getCarrierPackageForPhoneId(phoneId) == null) {
782             mConfigFromCarrierApp[phoneId] = null;
783         }
784         mHandler.sendMessage(mHandler.obtainMessage(EVENT_DO_FETCH_DEFAULT, phoneId, -1));
785     }
786 
787     @Override public
788     @NonNull
getConfigForSubId(int subId)789     PersistableBundle getConfigForSubId(int subId) {
790         // TODO(b/73136824): Migrate to TelephonyPermissions#checkCallingOrSelfReadPhoneState.
791         try {
792             mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, null);
793             // SKIP checking run-time READ_PHONE_STATE since using PRIVILEGED
794         } catch (SecurityException e) {
795             try {
796                 mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, null);
797             } catch (SecurityException securityException) {
798                 // If we don't have the runtime permission, but do have carrier privileges, that
799                 // suffices for reading phone state.
800                 if (!SubscriptionManager.isValidSubscriptionId(subId)) {
801                     throw securityException;
802                 }
803                 TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(subId, null);
804             }
805         }
806 
807         int phoneId = SubscriptionManager.getPhoneId(subId);
808         PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig();
809         if (SubscriptionManager.isValidPhoneId(phoneId)) {
810             PersistableBundle config = mConfigFromDefaultApp[phoneId];
811             if (config != null) {
812                 retConfig.putAll(config);
813                 retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
814             }
815             config = mConfigFromCarrierApp[phoneId];
816             if (config != null) {
817                 retConfig.putAll(config);
818                 retConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
819             }
820         }
821         return retConfig;
822     }
823 
824     @Override
notifyConfigChangedForSubId(int subId)825     public void notifyConfigChangedForSubId(int subId) {
826         int phoneId = SubscriptionManager.getPhoneId(subId);
827         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
828             log("Ignore invalid phoneId: " + phoneId + " for subId: " + subId);
829             return;
830         }
831         String callingPackageName = mContext.getPackageManager().getNameForUid(
832                 Binder.getCallingUid());
833         // TODO: Check that the calling packages is privileged for subId specifically.
834         int privilegeStatus = TelephonyManager.from(mContext).checkCarrierPrivilegesForPackage(
835                 callingPackageName);
836         // Requires the calling app to be either a carrier privileged app or
837         // system privileged app with MODIFY_PHONE_STATE permission.
838         if (privilegeStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
839             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
840                     "Require carrier privileges or MODIFY_PHONE_STATE permission.");
841         }
842 
843         // This method should block until deleting has completed, so that an error which prevents us
844         // from clearing the cache is passed back to the carrier app. With the files successfully
845         // deleted, this can return and we will eventually bind to the carrier app.
846         clearCachedConfigForPackage(callingPackageName);
847         updateConfigForPhoneId(phoneId);
848     }
849 
850     @Override
updateConfigForPhoneId(int phoneId, String simState)851     public void updateConfigForPhoneId(int phoneId, String simState) {
852         mContext.enforceCallingOrSelfPermission(
853                 android.Manifest.permission.MODIFY_PHONE_STATE, null);
854         log("update config for phoneId: " + phoneId + " simState: " + simState);
855         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
856             return;
857         }
858         // requires Java 7 for switch on string.
859         switch (simState) {
860             case IccCardConstants.INTENT_VALUE_ICC_ABSENT:
861             case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR:
862             case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED:
863             case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN:
864                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CLEAR_CONFIG, phoneId, -1));
865                 break;
866             case IccCardConstants.INTENT_VALUE_ICC_LOADED:
867             case IccCardConstants.INTENT_VALUE_ICC_LOCKED:
868                 updateConfigForPhoneId(phoneId);
869                 break;
870         }
871     }
872 
873     @Override
getDefaultCarrierServicePackageName()874     public String getDefaultCarrierServicePackageName() {
875         return mPlatformCarrierConfigPackage;
876     }
877 
878     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)879     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
880         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
881                 != PackageManager.PERMISSION_GRANTED) {
882             pw.println("Permission Denial: can't dump carrierconfig from from pid="
883                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
884             return;
885         }
886         pw.println("CarrierConfigLoader: " + this);
887         for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
888             pw.println("Phone Id = " + i);
889             // display default values in CarrierConfigManager
890             printConfig(CarrierConfigManager.getDefaultConfig(), pw,
891                     "Default Values from CarrierConfigManager");
892             pw.println("");
893             // display ConfigFromDefaultApp
894             printConfig(mConfigFromDefaultApp[i], pw, "mConfigFromDefaultApp");
895             pw.println("");
896             // display ConfigFromCarrierApp
897             printConfig(mConfigFromCarrierApp[i], pw, "mConfigFromCarrierApp");
898         }
899     }
900 
printConfig(PersistableBundle configApp, PrintWriter pw, String name)901     private void printConfig(PersistableBundle configApp, PrintWriter pw, String name) {
902         IndentingPrintWriter indentPW = new IndentingPrintWriter(pw, "    ");
903         if (configApp == null) {
904             indentPW.increaseIndent();
905             indentPW.println(name + " : null ");
906             return;
907         }
908         indentPW.increaseIndent();
909         indentPW.println(name + " : ");
910         List<String> sortedKeys = new ArrayList<String>(configApp.keySet());
911         Collections.sort(sortedKeys);
912         indentPW.increaseIndent();
913         indentPW.increaseIndent();
914         for (String key : sortedKeys) {
915             if (configApp.get(key) != null && configApp.get(key) instanceof Object[]) {
916                 indentPW.println(key + " = " +
917                         Arrays.toString((Object[]) configApp.get(key)));
918             } else if (configApp.get(key) != null && configApp.get(key) instanceof int[]) {
919                 indentPW.println(key + " = " + Arrays.toString((int[]) configApp.get(key)));
920             } else {
921                 indentPW.println(key + " = " + configApp.get(key));
922             }
923         }
924     }
925 
926     private class CarrierServiceConnection implements ServiceConnection {
927         int phoneId;
928         int eventId;
929         IBinder service;
930 
CarrierServiceConnection(int phoneId, int eventId)931         public CarrierServiceConnection(int phoneId, int eventId) {
932             this.phoneId = phoneId;
933             this.eventId = eventId;
934         }
935 
936         @Override
onServiceConnected(ComponentName name, IBinder service)937         public void onServiceConnected(ComponentName name, IBinder service) {
938             log("Connected to config app: " + name.flattenToString());
939             this.service = service;
940             mHandler.sendMessage(mHandler.obtainMessage(eventId, phoneId, -1, this));
941         }
942 
943         @Override
onServiceDisconnected(ComponentName name)944         public void onServiceDisconnected(ComponentName name) {
945             this.service = null;
946         }
947     }
948 
949     private class ConfigLoaderBroadcastReceiver extends BroadcastReceiver {
950         @Override
onReceive(Context context, Intent intent)951         public void onReceive(Context context, Intent intent) {
952             String action = intent.getAction();
953             boolean replace = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
954             // If replace is true, only care ACTION_PACKAGE_REPLACED.
955             if (replace && !Intent.ACTION_PACKAGE_REPLACED.equals(action))
956                 return;
957 
958             switch (action) {
959                 case Intent.ACTION_BOOT_COMPLETED:
960                     mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_UNLOCKED, null));
961                     break;
962 
963                 case Intent.ACTION_PACKAGE_ADDED:
964                 case Intent.ACTION_PACKAGE_REMOVED:
965                 case Intent.ACTION_PACKAGE_REPLACED:
966                     int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
967                     String packageName = mContext.getPackageManager().getNameForUid(uid);
968                     if (packageName != null) {
969                         // We don't have a phoneId for arg1.
970                         mHandler.sendMessage(
971                                 mHandler.obtainMessage(EVENT_PACKAGE_CHANGED, packageName));
972                     }
973                     break;
974             }
975         }
976     }
977 
log(String msg)978     private static void log(String msg) {
979         Log.d(LOG_TAG, msg);
980     }
981 
loge(String msg)982     private static void loge(String msg) {
983         Log.e(LOG_TAG, msg);
984     }
985 }
986