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