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