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