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