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