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