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