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 if (config == null) { 476 config = new PersistableBundle(); 477 } 478 479 final String version = getPackageVersion(packageName); 480 if (version == null) { 481 loge("Failed to get package version for: " + packageName); 482 return; 483 } 484 485 FileOutputStream outFile = null; 486 try { 487 outFile = new FileOutputStream( 488 new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid))); 489 FastXmlSerializer out = new FastXmlSerializer(); 490 out.setOutput(outFile, "utf-8"); 491 out.startDocument("utf-8", true); 492 out.startTag(null, TAG_DOCUMENT); 493 out.startTag(null, TAG_VERSION); 494 out.text(version); 495 out.endTag(null, TAG_VERSION); 496 out.startTag(null, TAG_BUNDLE); 497 config.saveToXml(out); 498 out.endTag(null, TAG_BUNDLE); 499 out.endTag(null, TAG_DOCUMENT); 500 out.endDocument(); 501 out.flush(); 502 outFile.close(); 503 } 504 catch (IOException e) { 505 loge(e.toString()); 506 } 507 catch (XmlPullParserException e) { 508 loge(e.toString()); 509 } 510 } 511 512 /** 513 * Reads a bundle from an XML file. 514 * 515 * This restores a bundle that was written with {@link #saveConfigToXml}. This returns the saved 516 * config bundle for the given package and ICCID. 517 * 518 * In case of errors, or if the saved config is from a different package version than the 519 * current version, then null will be returned. 520 * 521 * @param packageName the name of the package from which we fetched this bundle. 522 * @param iccid the ICCID of the subscription for which this bundle was fetched. 523 * @return the bundle from the XML file. Returns null if there is no saved config, the saved 524 * version does not match, or reading config fails. 525 */ restoreConfigFromXml(String packageName, String iccid)526 private PersistableBundle restoreConfigFromXml(String packageName, String iccid) { 527 final String version = getPackageVersion(packageName); 528 if (version == null) { 529 loge("Failed to get package version for: " + packageName); 530 return null; 531 } 532 if (packageName == null || iccid == null) { 533 loge("Cannot restore config with null packageName or iccid."); 534 return null; 535 } 536 537 PersistableBundle restoredBundle = null; 538 FileInputStream inFile = null; 539 try { 540 inFile = new FileInputStream( 541 new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid))); 542 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); 543 parser.setInput(inFile, "utf-8"); 544 545 int event; 546 while (((event = parser.next()) != XmlPullParser.END_DOCUMENT)) { 547 548 if (event == XmlPullParser.START_TAG && TAG_VERSION.equals(parser.getName())) { 549 String savedVersion = parser.nextText(); 550 if (!version.equals(savedVersion)) { 551 log("Saved version mismatch: " + version + " vs " + savedVersion); 552 break; 553 } 554 } 555 556 if (event == XmlPullParser.START_TAG && TAG_BUNDLE.equals(parser.getName())) { 557 restoredBundle = PersistableBundle.restoreFromXml(parser); 558 } 559 } 560 inFile.close(); 561 } 562 catch (FileNotFoundException e) { 563 loge(e.toString()); 564 } 565 catch (XmlPullParserException e) { 566 loge(e.toString()); 567 } 568 catch (IOException e) { 569 loge(e.toString()); 570 } 571 572 return restoredBundle; 573 } 574 575 /** 576 * Clears cached carrier config. 577 * This deletes all saved XML files associated with the given package name. If packageName is 578 * null, then it deletes all saved XML files. 579 * 580 * @param packageName the name of a carrier package, or null if all cached config should be 581 * cleared. 582 * @return true iff one or more files were deleted. 583 */ clearCachedConfigForPackage(final String packageName)584 private boolean clearCachedConfigForPackage(final String packageName) { 585 File dir = mContext.getFilesDir(); 586 File[] packageFiles = dir.listFiles(new FilenameFilter() { 587 public boolean accept(File dir, String filename) { 588 if (packageName != null) { 589 return filename.startsWith("carrierconfig-" + packageName + "-"); 590 } else { 591 return filename.startsWith("carrierconfig-"); 592 } 593 } 594 }); 595 if (packageFiles == null || packageFiles.length < 1) return false; 596 for (File f : packageFiles) { 597 log("deleting " + f.getName()); 598 f.delete(); 599 } 600 return true; 601 } 602 603 /** Builds a canonical file name for a config file. */ getFilenameForConfig(@onNull String packageName, @NonNull String iccid)604 private String getFilenameForConfig(@NonNull String packageName, @NonNull String iccid) { 605 return "carrierconfig-" + packageName + "-" + iccid + ".xml"; 606 } 607 608 /** Return the current version code of a package, or null if the name is not found. */ getPackageVersion(String packageName)609 private String getPackageVersion(String packageName) { 610 try { 611 PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0); 612 return Integer.toString(info.versionCode); 613 } catch (PackageManager.NameNotFoundException e) { 614 return null; 615 } 616 } 617 618 /** Read up to date config. 619 * 620 * This reads config bundles for the given phoneId. That means getting the latest bundle from 621 * the default app and a privileged carrier app, if present. This will not bind to an app if we 622 * have a saved config file to use instead. 623 */ updateConfigForPhoneId(int phoneId)624 private void updateConfigForPhoneId(int phoneId) { 625 // Clear in-memory cache for carrier app config, so when carrier app gets uninstalled, no 626 // stale config is left. 627 if (mConfigFromCarrierApp[phoneId] != null && 628 getCarrierPackageForPhoneId(phoneId) == null) { 629 mConfigFromCarrierApp[phoneId] = null; 630 } 631 mHandler.sendMessage(mHandler.obtainMessage(EVENT_FETCH_DEFAULT, phoneId, -1)); 632 } 633 634 @Override public 635 @NonNull getConfigForSubId(int subId)636 PersistableBundle getConfigForSubId(int subId) { 637 try { 638 mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE, null); 639 // SKIP checking run-time READ_PHONE_STATE since using PRIVILEGED 640 } catch (SecurityException e) { 641 mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, null); 642 } 643 int phoneId = SubscriptionManager.getPhoneId(subId); 644 PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig(); 645 if (SubscriptionManager.isValidPhoneId(phoneId)) { 646 PersistableBundle config = mConfigFromDefaultApp[phoneId]; 647 if (config != null) 648 retConfig.putAll(config); 649 config = mConfigFromCarrierApp[phoneId]; 650 if (config != null) 651 retConfig.putAll(config); 652 } 653 return retConfig; 654 } 655 656 @Override notifyConfigChangedForSubId(int subId)657 public void notifyConfigChangedForSubId(int subId) { 658 int phoneId = SubscriptionManager.getPhoneId(subId); 659 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 660 log("Ignore invalid phoneId: " + phoneId + " for subId: " + subId); 661 return; 662 } 663 String callingPackageName = mContext.getPackageManager().getNameForUid( 664 Binder.getCallingUid()); 665 // TODO: Check that the calling packages is privileged for subId specifically. 666 int privilegeStatus = TelephonyManager.from(mContext).checkCarrierPrivilegesForPackage( 667 callingPackageName); 668 if (privilegeStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 669 throw new SecurityException( 670 "Package is not privileged for subId=" + subId + ": " + callingPackageName); 671 } 672 673 // This method should block until deleting has completed, so that an error which prevents us 674 // from clearing the cache is passed back to the carrier app. With the files successfully 675 // deleted, this can return and we will eventually bind to the carrier app. 676 clearCachedConfigForPackage(callingPackageName); 677 updateConfigForPhoneId(phoneId); 678 } 679 680 @Override updateConfigForPhoneId(int phoneId, String simState)681 public void updateConfigForPhoneId(int phoneId, String simState) { 682 mContext.enforceCallingOrSelfPermission( 683 android.Manifest.permission.MODIFY_PHONE_STATE, null); 684 log("update config for phoneId: " + phoneId + " simState: " + simState); 685 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 686 return; 687 } 688 // requires Java 7 for switch on string. 689 switch (simState) { 690 case IccCardConstants.INTENT_VALUE_ICC_ABSENT: 691 case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR: 692 case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN: 693 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CLEAR_CONFIG, phoneId, -1)); 694 break; 695 case IccCardConstants.INTENT_VALUE_ICC_LOADED: 696 case IccCardConstants.INTENT_VALUE_ICC_LOCKED: 697 updateConfigForPhoneId(phoneId); 698 break; 699 } 700 } 701 702 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)703 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 704 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 705 != PackageManager.PERMISSION_GRANTED) { 706 pw.println("Permission Denial: can't dump carrierconfig from from pid=" 707 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 708 return; 709 } 710 pw.println("CarrierConfigLoader: " + this); 711 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) { 712 pw.println(" Phone Id=" + i); 713 pw.println(" mConfigFromDefaultApp=" + mConfigFromDefaultApp[i]); 714 pw.println(" mConfigFromCarrierApp=" + mConfigFromCarrierApp[i]); 715 } 716 } 717 718 private class CarrierServiceConnection implements ServiceConnection { 719 int phoneId; 720 int eventId; 721 IBinder service; 722 CarrierServiceConnection(int phoneId, int eventId)723 public CarrierServiceConnection(int phoneId, int eventId) { 724 this.phoneId = phoneId; 725 this.eventId = eventId; 726 } 727 728 @Override onServiceConnected(ComponentName name, IBinder service)729 public void onServiceConnected(ComponentName name, IBinder service) { 730 log("Connected to config app: " + name.flattenToString()); 731 this.service = service; 732 mHandler.sendMessage(mHandler.obtainMessage(eventId, phoneId, -1, this)); 733 } 734 735 @Override onServiceDisconnected(ComponentName name)736 public void onServiceDisconnected(ComponentName name) { 737 this.service = null; 738 } 739 } 740 741 private class ConfigLoaderBroadcastReceiver extends BroadcastReceiver { 742 @Override onReceive(Context context, Intent intent)743 public void onReceive(Context context, Intent intent) { 744 String action = intent.getAction(); 745 boolean replace = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); 746 // If replace is true, only care ACTION_PACKAGE_REPLACED. 747 if (replace && !Intent.ACTION_PACKAGE_REPLACED.equals(action)) 748 return; 749 750 switch (action) { 751 case Intent.ACTION_BOOT_COMPLETED: 752 mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_UNLOCKED, null)); 753 break; 754 755 case Intent.ACTION_PACKAGE_ADDED: 756 case Intent.ACTION_PACKAGE_REMOVED: 757 case Intent.ACTION_PACKAGE_REPLACED: 758 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 759 String packageName = mContext.getPackageManager().getNameForUid(uid); 760 if (packageName != null) { 761 // We don't have a phoneId for arg1. 762 mHandler.sendMessage( 763 mHandler.obtainMessage(EVENT_PACKAGE_CHANGED, packageName)); 764 } 765 break; 766 } 767 } 768 } 769 log(String msg)770 private static void log(String msg) { 771 Log.d(LOG_TAG, msg); 772 } 773 loge(String msg)774 private static void loge(String msg) { 775 Log.e(LOG_TAG, msg); 776 } 777 } 778