Home | History | Annotate | Download | only in phone
      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 
     22 import android.annotation.NonNull;
     23 import android.app.ActivityManagerNative;
     24 import android.content.BroadcastReceiver;
     25 import android.content.ComponentName;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.IntentFilter;
     29 import android.content.ServiceConnection;
     30 import android.content.SharedPreferences;
     31 import android.content.pm.PackageInfo;
     32 import android.content.pm.PackageManager;
     33 import android.database.sqlite.SQLiteDatabase;
     34 import android.database.sqlite.SQLiteOpenHelper;
     35 import android.os.AsyncResult;
     36 import android.os.Binder;
     37 import android.os.Build;
     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.ServiceManager;
     44 import android.os.UserHandle;
     45 import android.preference.PreferenceManager;
     46 import android.service.carrier.CarrierIdentifier;
     47 import android.service.carrier.CarrierService;
     48 import android.service.carrier.ICarrierService;
     49 import android.telephony.CarrierConfigManager;
     50 import android.telephony.SubscriptionManager;
     51 import android.telephony.TelephonyManager;
     52 import android.util.Log;
     53 
     54 import com.android.internal.telephony.ICarrierConfigLoader;
     55 import com.android.internal.telephony.IccCardConstants;
     56 import com.android.internal.telephony.Phone;
     57 import com.android.internal.telephony.PhoneConstants;
     58 import com.android.internal.telephony.PhoneFactory;
     59 import com.android.internal.telephony.TelephonyIntents;
     60 import com.android.internal.util.FastXmlSerializer;
     61 
     62 import org.xmlpull.v1.XmlPullParser;
     63 import org.xmlpull.v1.XmlPullParserException;
     64 import org.xmlpull.v1.XmlPullParserFactory;
     65 
     66 import java.io.File;
     67 import java.io.FileDescriptor;
     68 import java.io.FileInputStream;
     69 import java.io.FileNotFoundException;
     70 import java.io.FileOutputStream;
     71 import java.io.FilenameFilter;
     72 import java.io.IOException;
     73 import java.io.PrintWriter;
     74 import java.util.List;
     75 
     76 /**
     77  * CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays.
     78  */
     79 
     80 public class CarrierConfigLoader extends ICarrierConfigLoader.Stub {
     81     private static final String LOG_TAG = "CarrierConfigLoader";
     82     // Package name for default carrier config app, bundled with system image.
     83     private static final String DEFAULT_CARRIER_CONFIG_PACKAGE = "com.android.carrierconfig";
     84 
     85     /** The singleton instance. */
     86     private static CarrierConfigLoader sInstance;
     87     // The context for phone app, passed from PhoneGlobals.
     88     private Context mContext;
     89     // Carrier configs from default app, indexed by phoneID.
     90     private PersistableBundle[] mConfigFromDefaultApp;
     91     // Carrier configs from privileged carrier config app, indexed by phoneID.
     92     private PersistableBundle[] mConfigFromCarrierApp;
     93     // Service connection for binding to config app.
     94     private CarrierServiceConnection[] mServiceConnection;
     95 
     96     // Broadcast receiver for Boot intents, register intent filter in construtor.
     97     private final BroadcastReceiver mBootReceiver = new ConfigLoaderBroadcastReceiver();
     98     // Broadcast receiver for SIM and pkg intents, register intent filter in constructor.
     99     private final BroadcastReceiver mPackageReceiver = new ConfigLoaderBroadcastReceiver();
    100 
    101     // Message codes; see mHandler below.
    102     // Request from SubscriptionInfoUpdater when SIM becomes absent or error.
    103     private static final int EVENT_CLEAR_CONFIG = 0;
    104     // Has connected to default app.
    105     private static final int EVENT_CONNECTED_TO_DEFAULT = 3;
    106     // Has connected to carrier app.
    107     private static final int EVENT_CONNECTED_TO_CARRIER = 4;
    108     // Config has been loaded from default app.
    109     private static final int EVENT_LOADED_FROM_DEFAULT = 5;
    110     // Config has been loaded from carrier app.
    111     private static final int EVENT_LOADED_FROM_CARRIER = 6;
    112     // Attempt to fetch from default app or read from XML.
    113     private static final int EVENT_FETCH_DEFAULT = 7;
    114     // Attempt to fetch from carrier app or read from XML.
    115     private static final int EVENT_FETCH_CARRIER = 8;
    116     // A package has been installed, uninstalled, or updated.
    117     private static final int EVENT_PACKAGE_CHANGED = 9;
    118     // Bind timed out for the default app.
    119     private static final int EVENT_BIND_DEFAULT_TIMEOUT = 10;
    120     // Bind timed out for a carrier app.
    121     private static final int EVENT_BIND_CARRIER_TIMEOUT = 11;
    122     // Check if the system fingerprint has changed.
    123     private static final int EVENT_CHECK_SYSTEM_UPDATE = 12;
    124     // Rerun carrier config binding after system is unlocked.
    125     private static final int EVENT_SYSTEM_UNLOCKED = 13;
    126 
    127     private static final int BIND_TIMEOUT_MILLIS = 30000;
    128 
    129     // Tags used for saving and restoring XML documents.
    130     private static final String TAG_DOCUMENT = "carrier_config";
    131     private static final String TAG_VERSION = "package_version";
    132     private static final String TAG_BUNDLE = "bundle_data";
    133 
    134     // SharedPreferences key for last known build fingerprint.
    135     private static final String KEY_FINGERPRINT = "build_fingerprint";
    136 
    137     // Handler to process various events.
    138     //
    139     // For each phoneId, the event sequence should be:
    140     //     fetch default, connected to default, loaded from default,
    141     //     fetch carrier, connected to carrier, loaded from carrier.
    142     //
    143     // If there is a saved config file for either the default app or the carrier app, we skip
    144     // binding to the app and go straight from fetch to loaded.
    145     //
    146     // At any time, at most one connection is active. If events are not in this order, previous
    147     // connection will be unbound, so only latest event takes effect.
    148     //
    149     // We broadcast ACTION_CARRIER_CONFIG_CHANGED after:
    150     // 1. loading from carrier app (even if read from a file)
    151     // 2. loading from default app if there is no carrier app (even if read from a file)
    152     // 3. clearing config (e.g. due to sim removal)
    153     // 4. encountering bind or IPC error
    154     private Handler mHandler = new Handler() {
    155             @Override
    156         public void handleMessage(Message msg) {
    157             int phoneId = msg.arg1;
    158             log("mHandler: " + msg.what + " phoneId: " + phoneId);
    159             String iccid;
    160             CarrierIdentifier carrierId;
    161             String carrierPackageName;
    162             CarrierServiceConnection conn;
    163             PersistableBundle config;
    164             switch (msg.what) {
    165                 case EVENT_CLEAR_CONFIG:
    166                     if (mConfigFromDefaultApp[phoneId] == null &&
    167                         mConfigFromCarrierApp[phoneId] == null)
    168                         break;
    169                     mConfigFromDefaultApp[phoneId] = null;
    170                     mConfigFromCarrierApp[phoneId] = null;
    171                     mServiceConnection[phoneId] = null;
    172                     broadcastConfigChangedIntent(phoneId);
    173                     break;
    174 
    175                 case EVENT_SYSTEM_UNLOCKED:
    176                     for (int i = 0; i < TelephonyManager.from(mContext).getPhoneCount(); ++i) {
    177                         updateConfigForPhoneId(i);
    178                     }
    179                     break;
    180 
    181                 case EVENT_PACKAGE_CHANGED:
    182                     carrierPackageName = (String) msg.obj;
    183                     // Only update if there are cached config removed to avoid updating config
    184                     // for unrelated packages.
    185                     if (clearCachedConfigForPackage(carrierPackageName)) {
    186                         int numPhones = TelephonyManager.from(mContext).getPhoneCount();
    187                         for (int i = 0; i < numPhones; ++i) {
    188                             updateConfigForPhoneId(i);
    189                         }
    190                     }
    191                     break;
    192 
    193                 case EVENT_FETCH_DEFAULT:
    194                     iccid = getIccIdForPhoneId(phoneId);
    195                     config = restoreConfigFromXml(DEFAULT_CARRIER_CONFIG_PACKAGE, iccid);
    196                     if (config != null) {
    197                         log("Loaded config from XML. package=" + DEFAULT_CARRIER_CONFIG_PACKAGE
    198                                 + " phoneId=" + phoneId);
    199                         mConfigFromDefaultApp[phoneId] = config;
    200                         Message newMsg = obtainMessage(EVENT_LOADED_FROM_DEFAULT, phoneId, -1);
    201                         newMsg.getData().putBoolean("loaded_from_xml", true);
    202                         mHandler.sendMessage(newMsg);
    203                     } else {
    204                         if (bindToConfigPackage(DEFAULT_CARRIER_CONFIG_PACKAGE,
    205                                 phoneId, EVENT_CONNECTED_TO_DEFAULT)) {
    206                             sendMessageDelayed(obtainMessage(EVENT_BIND_DEFAULT_TIMEOUT, phoneId, -1),
    207                                     BIND_TIMEOUT_MILLIS);
    208                         } else {
    209                             // Send bcast if bind fails
    210                             broadcastConfigChangedIntent(phoneId);
    211                         }
    212                     }
    213                     break;
    214 
    215                 case EVENT_CONNECTED_TO_DEFAULT:
    216                     removeMessages(EVENT_BIND_DEFAULT_TIMEOUT);
    217                     carrierId = getCarrierIdForPhoneId(phoneId);
    218                     conn = (CarrierServiceConnection) msg.obj;
    219                     // If new service connection has been created, unbind.
    220                     if (mServiceConnection[phoneId] != conn || conn.service == null) {
    221                         mContext.unbindService(conn);
    222                         break;
    223                     }
    224                     try {
    225                         ICarrierService carrierService = ICarrierService.Stub
    226                                 .asInterface(conn.service);
    227                         config = carrierService.getCarrierConfig(carrierId);
    228                         iccid = getIccIdForPhoneId(phoneId);
    229                         saveConfigToXml(DEFAULT_CARRIER_CONFIG_PACKAGE, iccid, config);
    230                         mConfigFromDefaultApp[phoneId] = config;
    231                         sendMessage(obtainMessage(EVENT_LOADED_FROM_DEFAULT, phoneId, -1));
    232                     } catch (Exception ex) {
    233                         // The bound app could throw exceptions that binder will pass to us.
    234                         loge("Failed to get carrier config: " + ex.toString());
    235                     } finally {
    236                         mContext.unbindService(mServiceConnection[phoneId]);
    237                     }
    238                     break;
    239 
    240                 case EVENT_BIND_DEFAULT_TIMEOUT:
    241                     mContext.unbindService(mServiceConnection[phoneId]);
    242                     broadcastConfigChangedIntent(phoneId);
    243                     break;
    244 
    245                 case EVENT_LOADED_FROM_DEFAULT:
    246                     // If we attempted to bind to the app, but the service connection is null, then
    247                     // config was cleared while we were waiting and we should not continue.
    248                     if (!msg.getData().getBoolean("loaded_from_xml", false)
    249                             && mServiceConnection[phoneId] == null) {
    250                         break;
    251                     }
    252                     carrierPackageName = getCarrierPackageForPhoneId(phoneId);
    253                     if (carrierPackageName != null) {
    254                         log("Found carrier config app: " + carrierPackageName);
    255                         sendMessage(obtainMessage(EVENT_FETCH_CARRIER, phoneId));
    256                     } else {
    257                         broadcastConfigChangedIntent(phoneId);
    258                     }
    259                     break;
    260 
    261                 case EVENT_FETCH_CARRIER:
    262                     carrierPackageName = getCarrierPackageForPhoneId(phoneId);
    263                     iccid = getIccIdForPhoneId(phoneId);
    264                     config = restoreConfigFromXml(carrierPackageName, iccid);
    265                     if (config != null) {
    266                         log("Loaded config from XML. package=" + carrierPackageName + " phoneId="
    267                                 + phoneId);
    268                         mConfigFromCarrierApp[phoneId] = config;
    269                         Message newMsg = obtainMessage(EVENT_LOADED_FROM_CARRIER, phoneId, -1);
    270                         newMsg.getData().putBoolean("loaded_from_xml", true);
    271                         sendMessage(newMsg);
    272                     } else {
    273                         if (carrierPackageName != null
    274                             && bindToConfigPackage(carrierPackageName, phoneId,
    275                                     EVENT_CONNECTED_TO_CARRIER)) {
    276                             sendMessageDelayed(obtainMessage(EVENT_BIND_CARRIER_TIMEOUT, phoneId, -1),
    277                                     BIND_TIMEOUT_MILLIS);
    278                         } else {
    279                             // Send bcast if bind fails
    280                             broadcastConfigChangedIntent(phoneId);
    281                         }
    282                     }
    283                     break;
    284 
    285                 case EVENT_CONNECTED_TO_CARRIER:
    286                     removeMessages(EVENT_BIND_CARRIER_TIMEOUT);
    287                     carrierId = getCarrierIdForPhoneId(phoneId);
    288                     conn = (CarrierServiceConnection) msg.obj;
    289                     // If new service connection has been created, unbind.
    290                     if (mServiceConnection[phoneId] != conn ||
    291                             conn.service == null) {
    292                         mContext.unbindService(conn);
    293                         break;
    294                     }
    295                     try {
    296                         ICarrierService carrierService = ICarrierService.Stub
    297                                 .asInterface(conn.service);
    298                         config = carrierService.getCarrierConfig(carrierId);
    299                         carrierPackageName = getCarrierPackageForPhoneId(phoneId);
    300                         iccid = getIccIdForPhoneId(phoneId);
    301                         saveConfigToXml(carrierPackageName, iccid, config);
    302                         mConfigFromCarrierApp[phoneId] = config;
    303                         sendMessage(obtainMessage(EVENT_LOADED_FROM_CARRIER, phoneId, -1));
    304                     } catch (Exception ex) {
    305                         // The bound app could throw exceptions that binder will pass to us.
    306                         loge("Failed to get carrier config: " + ex.toString());
    307                     } finally {
    308                         mContext.unbindService(mServiceConnection[phoneId]);
    309                     }
    310                     break;
    311 
    312                 case EVENT_BIND_CARRIER_TIMEOUT:
    313                     mContext.unbindService(mServiceConnection[phoneId]);
    314                     broadcastConfigChangedIntent(phoneId);
    315                     break;
    316 
    317                 case EVENT_LOADED_FROM_CARRIER:
    318                     // If we attempted to bind to the app, but the service connection is null, then
    319                     // config was cleared while we were waiting and we should not continue.
    320                     if (!msg.getData().getBoolean("loaded_from_xml", false)
    321                             && mServiceConnection[phoneId] == null) {
    322                         break;
    323                     }
    324                     broadcastConfigChangedIntent(phoneId);
    325                     break;
    326 
    327                 case EVENT_CHECK_SYSTEM_UPDATE:
    328                     SharedPreferences sharedPrefs =
    329                             PreferenceManager.getDefaultSharedPreferences(mContext);
    330                     final String lastFingerprint = sharedPrefs.getString(KEY_FINGERPRINT, null);
    331                     if (!Build.FINGERPRINT.equals(lastFingerprint)) {
    332                         log("Build fingerprint changed. old: "
    333                                 + lastFingerprint + " new: " + Build.FINGERPRINT);
    334                         clearCachedConfigForPackage(null);
    335                         sharedPrefs.edit().putString(KEY_FINGERPRINT, Build.FINGERPRINT).apply();
    336                     }
    337                     break;
    338             }
    339         }
    340     };
    341 
    342     /**
    343      * Constructs a CarrierConfigLoader, registers it as a service, and registers a broadcast
    344      * receiver for relevant events.
    345      */
    346     private CarrierConfigLoader(Context context) {
    347         mContext = context;
    348 
    349         IntentFilter bootFilter = new IntentFilter();
    350         bootFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
    351         context.registerReceiver(mBootReceiver, bootFilter);
    352 
    353         // Register for package updates. Update app or uninstall app update will have all 3 intents,
    354         // in the order or removed, added, replaced, all with extra_replace set to true.
    355         IntentFilter pkgFilter = new IntentFilter();
    356         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
    357         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    358         pkgFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
    359         pkgFilter.addDataScheme("package");
    360         context.registerReceiverAsUser(mPackageReceiver, UserHandle.ALL, pkgFilter, null, null);
    361 
    362         int numPhones = TelephonyManager.from(context).getPhoneCount();
    363         mConfigFromDefaultApp = new PersistableBundle[numPhones];
    364         mConfigFromCarrierApp = new PersistableBundle[numPhones];
    365         mServiceConnection = new CarrierServiceConnection[numPhones];
    366         // Make this service available through ServiceManager.
    367         ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this);
    368         log("CarrierConfigLoader has started");
    369         mHandler.sendEmptyMessage(EVENT_CHECK_SYSTEM_UPDATE);
    370     }
    371 
    372     /**
    373      * Initialize the singleton CarrierConfigLoader instance.
    374      *
    375      * This is only done once, at startup, from {@link com.android.phone.PhoneApp#onCreate}.
    376      */
    377     /* package */
    378     static CarrierConfigLoader init(Context context) {
    379         synchronized (CarrierConfigLoader.class) {
    380             if (sInstance == null) {
    381                 sInstance = new CarrierConfigLoader(context);
    382             } else {
    383                 Log.wtf(LOG_TAG, "init() called multiple times!  sInstance = " + sInstance);
    384             }
    385             return sInstance;
    386         }
    387     }
    388 
    389     private void broadcastConfigChangedIntent(int phoneId) {
    390         Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
    391         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    392         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
    393         ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
    394                 UserHandle.USER_ALL);
    395     }
    396 
    397     /** Binds to the default or carrier config app. */
    398     private boolean bindToConfigPackage(String pkgName, int phoneId, int eventId) {
    399         log("Binding to " + pkgName + " for phone " + phoneId);
    400         Intent carrierService = new Intent(CarrierService.CARRIER_SERVICE_INTERFACE);
    401         carrierService.setPackage(pkgName);
    402         mServiceConnection[phoneId] = new CarrierServiceConnection(phoneId, eventId);
    403         try {
    404             return mContext.bindService(carrierService, mServiceConnection[phoneId],
    405                     Context.BIND_AUTO_CREATE);
    406         } catch (SecurityException ex) {
    407             return false;
    408         }
    409     }
    410 
    411     private CarrierIdentifier getCarrierIdForPhoneId(int phoneId) {
    412         String mcc = "";
    413         String mnc = "";
    414         String imsi = "";
    415         String gid1 = "";
    416         String gid2 = "";
    417         String spn = TelephonyManager.from(mContext).getSimOperatorNameForPhone(phoneId);
    418         String simOperator = TelephonyManager.from(mContext).getSimOperatorNumericForPhone(phoneId);
    419         // A valid simOperator should be 5 or 6 digits, depending on the length of the MNC.
    420         if (simOperator != null && simOperator.length() >= 3) {
    421             mcc = simOperator.substring(0, 3);
    422             mnc = simOperator.substring(3);
    423         }
    424         Phone phone = PhoneFactory.getPhone(phoneId);
    425         if (phone != null) {
    426             imsi = phone.getSubscriberId();
    427             gid1 = phone.getGroupIdLevel1();
    428             gid2 = phone.getGroupIdLevel2();
    429         }
    430 
    431         return new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2);
    432     }
    433 
    434     /** Returns the package name of a priveleged carrier app, or null if there is none. */
    435     private String getCarrierPackageForPhoneId(int phoneId) {
    436         List<String> carrierPackageNames = TelephonyManager.from(mContext)
    437                 .getCarrierPackageNamesForIntentAndPhone(
    438                         new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), phoneId);
    439         if (carrierPackageNames != null && carrierPackageNames.size() > 0) {
    440             return carrierPackageNames.get(0);
    441         } else {
    442             return null;
    443         }
    444     }
    445 
    446     private String getIccIdForPhoneId(int phoneId) {
    447         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
    448             return null;
    449         }
    450         Phone phone = PhoneFactory.getPhone(phoneId);
    451         if (phone == null) {
    452             return null;
    453         }
    454         return phone.getIccSerialNumber();
    455     }
    456 
    457     /**
    458      * Writes a bundle to an XML file.
    459      *
    460      * The bundle will be written to a file named after the package name and ICCID, so that it can
    461      * be restored later with {@link @restoreConfigFromXml}. The XML output will include the bundle
    462      * and the current version of the specified package.
    463      *
    464      * In case of errors or invalid input, no file will be written.
    465      *
    466      * @param packageName the name of the package from which we fetched this bundle.
    467      * @param iccid the ICCID of the subscription for which this bundle was fetched.
    468      * @param config the bundle to be written. Null will be treated as an empty bundle.
    469      */
    470     private void saveConfigToXml(String packageName, String iccid, PersistableBundle config) {
    471         if (packageName == null || iccid == null) {
    472             loge("Cannot save config with null packageName or iccid.");
    473             return;
    474         }
    475         if (config == null) {
    476           config = new PersistableBundle();
    477         }
    478 
    479         final String version = getPackageVersion(packageName);
    480         if (version == null) {
    481             loge("Failed to get package version for: " + packageName);
    482             return;
    483         }
    484 
    485         FileOutputStream outFile = null;
    486         try {
    487             outFile = new FileOutputStream(
    488                     new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid)));
    489             FastXmlSerializer out = new FastXmlSerializer();
    490             out.setOutput(outFile, "utf-8");
    491             out.startDocument("utf-8", true);
    492             out.startTag(null, TAG_DOCUMENT);
    493             out.startTag(null, TAG_VERSION);
    494             out.text(version);
    495             out.endTag(null, TAG_VERSION);
    496             out.startTag(null, TAG_BUNDLE);
    497             config.saveToXml(out);
    498             out.endTag(null, TAG_BUNDLE);
    499             out.endTag(null, TAG_DOCUMENT);
    500             out.endDocument();
    501             out.flush();
    502             outFile.close();
    503         }
    504         catch (IOException e) {
    505             loge(e.toString());
    506         }
    507         catch (XmlPullParserException e) {
    508             loge(e.toString());
    509         }
    510     }
    511 
    512     /**
    513      * Reads a bundle from an XML file.
    514      *
    515      * This restores a bundle that was written with {@link #saveConfigToXml}. This returns the saved
    516      * config bundle for the given package and ICCID.
    517      *
    518      * In case of errors, or if the saved config is from a different package version than the
    519      * current version, then null will be returned.
    520      *
    521      * @param packageName the name of the package from which we fetched this bundle.
    522      * @param iccid the ICCID of the subscription for which this bundle was fetched.
    523      * @return the bundle from the XML file. Returns null if there is no saved config, the saved
    524      *         version does not match, or reading config fails.
    525      */
    526     private PersistableBundle restoreConfigFromXml(String packageName, String iccid) {
    527         final String version = getPackageVersion(packageName);
    528         if (version == null) {
    529             loge("Failed to get package version for: " + packageName);
    530             return null;
    531         }
    532         if (packageName == null || iccid == null) {
    533             loge("Cannot restore config with null packageName or iccid.");
    534             return null;
    535         }
    536 
    537         PersistableBundle restoredBundle = null;
    538         FileInputStream inFile = null;
    539         try {
    540             inFile = new FileInputStream(
    541                     new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid)));
    542             XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
    543             parser.setInput(inFile, "utf-8");
    544 
    545             int event;
    546             while (((event = parser.next()) != XmlPullParser.END_DOCUMENT)) {
    547 
    548                 if (event == XmlPullParser.START_TAG && TAG_VERSION.equals(parser.getName())) {
    549                     String savedVersion = parser.nextText();
    550                     if (!version.equals(savedVersion)) {
    551                         log("Saved version mismatch: " + version + " vs " + savedVersion);
    552                         break;
    553                     }
    554                 }
    555 
    556                 if (event == XmlPullParser.START_TAG && TAG_BUNDLE.equals(parser.getName())) {
    557                     restoredBundle = PersistableBundle.restoreFromXml(parser);
    558                 }
    559             }
    560             inFile.close();
    561         }
    562         catch (FileNotFoundException e) {
    563             loge(e.toString());
    564         }
    565         catch (XmlPullParserException e) {
    566             loge(e.toString());
    567         }
    568         catch (IOException e) {
    569             loge(e.toString());
    570         }
    571 
    572         return restoredBundle;
    573     }
    574 
    575     /**
    576      * Clears cached carrier config.
    577      * This deletes all saved XML files associated with the given package name. If packageName is
    578      * null, then it deletes all saved XML files.
    579      *
    580      * @param packageName the name of a carrier package, or null if all cached config should be
    581      *                    cleared.
    582      * @return true iff one or more files were deleted.
    583      */
    584     private boolean clearCachedConfigForPackage(final String packageName) {
    585         File dir = mContext.getFilesDir();
    586         File[] packageFiles = dir.listFiles(new FilenameFilter() {
    587             public boolean accept(File dir, String filename) {
    588                 if (packageName != null) {
    589                     return filename.startsWith("carrierconfig-" + packageName + "-");
    590                 } else {
    591                     return filename.startsWith("carrierconfig-");
    592                 }
    593             }
    594         });
    595         if (packageFiles == null || packageFiles.length < 1) return false;
    596         for (File f : packageFiles) {
    597             log("deleting " + f.getName());
    598             f.delete();
    599         }
    600         return true;
    601     }
    602 
    603     /** Builds a canonical file name for a config file. */
    604     private String getFilenameForConfig(@NonNull String packageName, @NonNull String iccid) {
    605         return "carrierconfig-" + packageName + "-" + iccid + ".xml";
    606     }
    607 
    608     /** Return the current version code of a package, or null if the name is not found. */
    609     private String getPackageVersion(String packageName) {
    610         try {
    611             PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
    612             return Integer.toString(info.versionCode);
    613         } catch (PackageManager.NameNotFoundException e) {
    614             return null;
    615         }
    616     }
    617 
    618     /** Read up to date config.
    619      *
    620      * This reads config bundles for the given phoneId. That means getting the latest bundle from
    621      * the default app and a privileged carrier app, if present. This will not bind to an app if we
    622      * have a saved config file to use instead.
    623      */
    624     private void updateConfigForPhoneId(int phoneId) {
    625         // Clear in-memory cache for carrier app config, so when carrier app gets uninstalled, no
    626         // stale config is left.
    627         if (mConfigFromCarrierApp[phoneId] != null &&
    628                 getCarrierPackageForPhoneId(phoneId) == null) {
    629             mConfigFromCarrierApp[phoneId] = null;
    630         }
    631         mHandler.sendMessage(mHandler.obtainMessage(EVENT_FETCH_DEFAULT, phoneId, -1));
    632     }
    633 
    634     @Override public
    635     @NonNull
    636     PersistableBundle getConfigForSubId(int subId) {
    637         try {
    638             mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, null);
    639             // SKIP checking run-time READ_PHONE_STATE since using PRIVILEGED
    640         } catch (SecurityException e) {
    641             mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, null);
    642         }
    643         int phoneId = SubscriptionManager.getPhoneId(subId);
    644         PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig();
    645         if (SubscriptionManager.isValidPhoneId(phoneId)) {
    646             PersistableBundle config = mConfigFromDefaultApp[phoneId];
    647             if (config != null)
    648                 retConfig.putAll(config);
    649             config = mConfigFromCarrierApp[phoneId];
    650             if (config != null)
    651                 retConfig.putAll(config);
    652         }
    653         return retConfig;
    654     }
    655 
    656     @Override
    657     public void notifyConfigChangedForSubId(int subId) {
    658         int phoneId = SubscriptionManager.getPhoneId(subId);
    659         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
    660             log("Ignore invalid phoneId: " + phoneId + " for subId: " + subId);
    661             return;
    662         }
    663         String callingPackageName = mContext.getPackageManager().getNameForUid(
    664                 Binder.getCallingUid());
    665         // TODO: Check that the calling packages is privileged for subId specifically.
    666         int privilegeStatus = TelephonyManager.from(mContext).checkCarrierPrivilegesForPackage(
    667                 callingPackageName);
    668         // Requires the calling app to be either a carrier privileged app or
    669         // system privileged app with MODIFY_PHONE_STATE permission.
    670         if (privilegeStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
    671             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE,
    672                     "Require carrier privileges or MODIFY_PHONE_STATE permission.");
    673         }
    674 
    675         // This method should block until deleting has completed, so that an error which prevents us
    676         // from clearing the cache is passed back to the carrier app. With the files successfully
    677         // deleted, this can return and we will eventually bind to the carrier app.
    678         clearCachedConfigForPackage(callingPackageName);
    679         updateConfigForPhoneId(phoneId);
    680     }
    681 
    682     @Override
    683     public void updateConfigForPhoneId(int phoneId, String simState) {
    684         mContext.enforceCallingOrSelfPermission(
    685                 android.Manifest.permission.MODIFY_PHONE_STATE, null);
    686         log("update config for phoneId: " + phoneId + " simState: " + simState);
    687         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
    688             return;
    689         }
    690         // requires Java 7 for switch on string.
    691         switch (simState) {
    692             case IccCardConstants.INTENT_VALUE_ICC_ABSENT:
    693             case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR:
    694             case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED:
    695             case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN:
    696                 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CLEAR_CONFIG, phoneId, -1));
    697                 break;
    698             case IccCardConstants.INTENT_VALUE_ICC_LOADED:
    699             case IccCardConstants.INTENT_VALUE_ICC_LOCKED:
    700                 updateConfigForPhoneId(phoneId);
    701                 break;
    702         }
    703     }
    704 
    705     @Override
    706     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    707         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
    708                 != PackageManager.PERMISSION_GRANTED) {
    709             pw.println("Permission Denial: can't dump carrierconfig from from pid="
    710                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
    711             return;
    712         }
    713         pw.println("CarrierConfigLoader: " + this);
    714         for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
    715             pw.println("  Phone Id=" + i);
    716             pw.println("  mConfigFromDefaultApp=" + mConfigFromDefaultApp[i]);
    717             pw.println("  mConfigFromCarrierApp=" + mConfigFromCarrierApp[i]);
    718         }
    719     }
    720 
    721     private class CarrierServiceConnection implements ServiceConnection {
    722         int phoneId;
    723         int eventId;
    724         IBinder service;
    725 
    726         public CarrierServiceConnection(int phoneId, int eventId) {
    727             this.phoneId = phoneId;
    728             this.eventId = eventId;
    729         }
    730 
    731         @Override
    732         public void onServiceConnected(ComponentName name, IBinder service) {
    733             log("Connected to config app: " + name.flattenToString());
    734             this.service = service;
    735             mHandler.sendMessage(mHandler.obtainMessage(eventId, phoneId, -1, this));
    736         }
    737 
    738         @Override
    739         public void onServiceDisconnected(ComponentName name) {
    740             this.service = null;
    741         }
    742     }
    743 
    744     private class ConfigLoaderBroadcastReceiver extends BroadcastReceiver {
    745         @Override
    746         public void onReceive(Context context, Intent intent) {
    747             String action = intent.getAction();
    748             boolean replace = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
    749             // If replace is true, only care ACTION_PACKAGE_REPLACED.
    750             if (replace && !Intent.ACTION_PACKAGE_REPLACED.equals(action))
    751                 return;
    752 
    753             switch (action) {
    754                 case Intent.ACTION_BOOT_COMPLETED:
    755                     mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_UNLOCKED, null));
    756                     break;
    757 
    758                 case Intent.ACTION_PACKAGE_ADDED:
    759                 case Intent.ACTION_PACKAGE_REMOVED:
    760                 case Intent.ACTION_PACKAGE_REPLACED:
    761                     int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
    762                     String packageName = mContext.getPackageManager().getNameForUid(uid);
    763                     if (packageName != null) {
    764                         // We don't have a phoneId for arg1.
    765                         mHandler.sendMessage(
    766                                 mHandler.obtainMessage(EVENT_PACKAGE_CHANGED, packageName));
    767                     }
    768                     break;
    769             }
    770         }
    771     }
    772 
    773     private static void log(String msg) {
    774         Log.d(LOG_TAG, msg);
    775     }
    776 
    777     private static void loge(String msg) {
    778         Log.e(LOG_TAG, msg);
    779     }
    780 }
    781