1 /* 2 * Copyright (C) 2014 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.internal.telephony.uicc; 18 19 import android.annotation.Nullable; 20 import android.content.Intent; 21 import android.content.pm.PackageInfo; 22 import android.content.pm.PackageManager; 23 import android.content.pm.ResolveInfo; 24 import android.content.pm.Signature; 25 import android.os.AsyncResult; 26 import android.os.Binder; 27 import android.os.Handler; 28 import android.os.Message; 29 import android.telephony.Rlog; 30 import android.telephony.TelephonyManager; 31 import android.text.TextUtils; 32 33 import com.android.internal.telephony.CommandException; 34 35 import java.io.FileDescriptor; 36 import java.io.PrintWriter; 37 import java.security.MessageDigest; 38 import java.security.NoSuchAlgorithmException; 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.List; 42 import java.util.Locale; 43 import java.util.concurrent.atomic.AtomicInteger; 44 45 /** 46 * Class that reads and stores the carrier privileged rules from the UICC. 47 * 48 * The rules are read when the class is created, hence it should only be created 49 * after the UICC can be read. And it should be deleted when a UICC is changed. 50 * 51 * Document: https://source.android.com/devices/tech/config/uicc.html 52 * 53 * {@hide} 54 */ 55 public class UiccCarrierPrivilegeRules extends Handler { 56 private static final String LOG_TAG = "UiccCarrierPrivilegeRules"; 57 private static final boolean DBG = false; 58 59 private static final String AID = "A00000015141434C00"; 60 private static final int CLA = 0x80; 61 private static final int COMMAND = 0xCA; 62 private static final int P1 = 0xFF; 63 private static final int P2 = 0x40; 64 private static final int P2_EXTENDED_DATA = 0x60; 65 private static final int P3 = 0x00; 66 private static final String DATA = ""; 67 68 /* 69 * Rules format: 70 * ALL_REF_AR_DO = TAG_ALL_REF_AR_DO + len + [REF_AR_DO]*n 71 * REF_AR_DO = TAG_REF_AR_DO + len + REF-DO + AR-DO 72 * 73 * REF_DO = TAG_REF_DO + len + DEVICE_APP_ID_REF_DO + (optional) PKG_REF_DO 74 * AR_DO = TAG_AR_DO + len + PERM_AR_DO 75 * 76 * DEVICE_APP_ID_REF_DO = TAG_DEVICE_APP_ID_REF_DO + len + sha256 hexstring of cert 77 * PKG_REF_DO = TAG_PKG_REF_DO + len + package name 78 * PERM_AR_DO = TAG_PERM_AR_DO + len + detailed permission (8 bytes) 79 * 80 * Data objects hierarchy by TAG: 81 * FF40 82 * E2 83 * E1 84 * C1 85 * CA 86 * E3 87 * DB 88 */ 89 // Values from the data standard. 90 private static final String TAG_ALL_REF_AR_DO = "FF40"; 91 private static final String TAG_REF_AR_DO = "E2"; 92 private static final String TAG_REF_DO = "E1"; 93 private static final String TAG_DEVICE_APP_ID_REF_DO = "C1"; 94 private static final String TAG_PKG_REF_DO = "CA"; 95 private static final String TAG_AR_DO = "E3"; 96 private static final String TAG_PERM_AR_DO = "DB"; 97 98 private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 1; 99 private static final int EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE = 2; 100 private static final int EVENT_CLOSE_LOGICAL_CHANNEL_DONE = 3; 101 private static final int EVENT_PKCS15_READ_DONE = 4; 102 103 // State of the object. 104 private static final int STATE_LOADING = 0; 105 private static final int STATE_LOADED = 1; 106 private static final int STATE_ERROR = 2; 107 108 // Max number of retries for open logical channel, interval is 10s. 109 private static final int MAX_RETRY = 1; 110 private static final int RETRY_INTERVAL_MS = 10000; 111 112 // Describes a single rule. 113 private static class AccessRule { 114 public byte[] certificateHash; 115 public String packageName; 116 public long accessType; // This bit is not currently used, but reserved for future use. 117 118 AccessRule(byte[] certificateHash, String packageName, long accessType) { 119 this.certificateHash = certificateHash; 120 this.packageName = packageName; 121 this.accessType = accessType; 122 } 123 124 boolean matches(byte[] certHash, String packageName) { 125 return certHash != null && Arrays.equals(this.certificateHash, certHash) && 126 (TextUtils.isEmpty(this.packageName) || this.packageName.equals(packageName)); 127 } 128 129 @Override 130 public String toString() { 131 return "cert: " + IccUtils.bytesToHexString(certificateHash) + " pkg: " + 132 packageName + " access: " + accessType; 133 } 134 } 135 136 // Used for parsing the data from the UICC. 137 public static class TLV { 138 private static final int SINGLE_BYTE_MAX_LENGTH = 0x80; 139 private String tag; 140 // Length encoding is in GPC_Specification_2.2.1: 11.1.5 APDU Message and Data Length. 141 // Length field could be either 1 byte if length < 128, or multiple bytes with first byte 142 // specifying how many bytes are used for length, followed by length bytes. 143 // Bytes for the length field, in ASCII HEX string form. 144 private String lengthBytes; 145 // Decoded length as integer. 146 private Integer length; 147 private String value; 148 149 public TLV(String tag) { 150 this.tag = tag; 151 } 152 153 public String getValue() { 154 if (value == null) return ""; 155 return value; 156 } 157 158 public String parseLength(String data) { 159 int offset = tag.length(); 160 int firstByte = Integer.parseInt(data.substring(offset, offset + 2), 16); 161 if (firstByte < SINGLE_BYTE_MAX_LENGTH) { 162 length = firstByte * 2; 163 lengthBytes = data.substring(offset, offset + 2); 164 } else { 165 int numBytes = firstByte - SINGLE_BYTE_MAX_LENGTH; 166 length = Integer.parseInt(data.substring(offset + 2, offset + 2 + numBytes * 2), 16) * 2; 167 lengthBytes = data.substring(offset, offset + 2 + numBytes * 2); 168 } 169 log("TLV parseLength length=" + length + "lenghtBytes: " + lengthBytes); 170 return lengthBytes; 171 } 172 173 public String parse(String data, boolean shouldConsumeAll) { 174 log("Parse TLV: " + tag); 175 if (!data.startsWith(tag)) { 176 throw new IllegalArgumentException("Tags don't match."); 177 } 178 int index = tag.length(); 179 if (index + 2 > data.length()) { 180 throw new IllegalArgumentException("No length."); 181 } 182 183 parseLength(data); 184 index += lengthBytes.length(); 185 186 log("index="+index+" length="+length+"data.length="+data.length()); 187 int remainingLength = data.length() - (index + length); 188 if (remainingLength < 0) { 189 throw new IllegalArgumentException("Not enough data."); 190 } 191 if (shouldConsumeAll && (remainingLength != 0)) { 192 throw new IllegalArgumentException("Did not consume all."); 193 } 194 value = data.substring(index, index + length); 195 196 log("Got TLV: " + tag + "," + length + "," + value); 197 198 return data.substring(index + length); 199 } 200 } 201 202 private UiccCard mUiccCard; // Parent 203 private UiccPkcs15 mUiccPkcs15; // ARF fallback 204 private AtomicInteger mState; 205 private List<AccessRule> mAccessRules; 206 private String mRules; 207 private Message mLoadedCallback; 208 private String mStatusMessage; // Only used for debugging. 209 private int mChannelId; // Channel Id for communicating with UICC. 210 private int mRetryCount; // Number of retries for open logical channel. 211 private final Runnable mRetryRunnable = new Runnable() { 212 @Override 213 public void run() { 214 openChannel(); 215 } 216 }; 217 218 private void openChannel() { 219 // Send open logical channel request. 220 int p2 = 0x00; 221 mUiccCard.iccOpenLogicalChannel(AID, p2, /* supported p2 value */ 222 obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, null)); 223 } 224 225 public UiccCarrierPrivilegeRules(UiccCard uiccCard, Message loadedCallback) { 226 log("Creating UiccCarrierPrivilegeRules"); 227 mUiccCard = uiccCard; 228 mState = new AtomicInteger(STATE_LOADING); 229 mStatusMessage = "Not loaded."; 230 mLoadedCallback = loadedCallback; 231 mRules = ""; 232 mAccessRules = new ArrayList<AccessRule>(); 233 234 openChannel(); 235 } 236 237 /** 238 * Returns true if the carrier privilege rules have finished loading. 239 */ 240 public boolean areCarrierPriviligeRulesLoaded() { 241 return mState.get() != STATE_LOADING; 242 } 243 244 /** 245 * Returns true if the carrier privilege rules have finished loading and some rules were 246 * specified. 247 */ 248 public boolean hasCarrierPrivilegeRules() { 249 return mState.get() != STATE_LOADING && mAccessRules != null && mAccessRules.size() > 0; 250 } 251 252 /** 253 * Returns package names for privilege rules. 254 * Return empty list if no rules defined or package name is empty string. 255 */ 256 public List<String> getPackageNames() { 257 List<String> pkgNames = new ArrayList<String>(); 258 if (mAccessRules != null) { 259 for (AccessRule ar : mAccessRules) { 260 if(!TextUtils.isEmpty(ar.packageName)) { 261 pkgNames.add(ar.packageName); 262 } 263 } 264 } 265 return pkgNames; 266 } 267 268 /** 269 * Returns the status of the carrier privileges for the input certificate and package name. 270 * 271 * @param signature The signature of the certificate. 272 * @param packageName name of the package. 273 * @return Access status. 274 */ 275 public int getCarrierPrivilegeStatus(Signature signature, String packageName) { 276 int state = mState.get(); 277 if (state == STATE_LOADING) { 278 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED; 279 } else if (state == STATE_ERROR) { 280 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES; 281 } 282 283 // SHA-1 is for backward compatible support only, strongly discouraged for new use. 284 byte[] certHash = getCertHash(signature, "SHA-1"); 285 byte[] certHash256 = getCertHash(signature, "SHA-256"); 286 for (AccessRule ar : mAccessRules) { 287 if (ar.matches(certHash, packageName) || ar.matches(certHash256, packageName)) { 288 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 289 } 290 } 291 292 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 293 } 294 295 /** 296 * Returns the status of the carrier privileges for the input package name. 297 * 298 * @param packageManager PackageManager for getting signatures. 299 * @param packageName name of the package. 300 * @return Access status. 301 */ 302 public int getCarrierPrivilegeStatus(PackageManager packageManager, String packageName) { 303 try { 304 // Short-circuit if there are no rules to check against, so we don't need to fetch 305 // the package info with signatures. 306 if (!hasCarrierPrivilegeRules()) { 307 int state = mState.get(); 308 if (state == STATE_LOADING) { 309 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED; 310 } else if (state == STATE_ERROR) { 311 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES; 312 } 313 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 314 } 315 // Include DISABLED_UNTIL_USED components. This facilitates cases where a carrier app 316 // is disabled by default, and some other component wants to enable it when it has 317 // gained carrier privileges (as an indication that a matching SIM has been inserted). 318 PackageInfo pInfo = packageManager.getPackageInfo(packageName, 319 PackageManager.GET_SIGNATURES | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); 320 return getCarrierPrivilegeStatus(pInfo); 321 } catch (PackageManager.NameNotFoundException ex) { 322 Rlog.e(LOG_TAG, "NameNotFoundException", ex); 323 } 324 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 325 } 326 327 /** 328 * Returns the status of the carrier privileges for the input package info. 329 * 330 * @param packageInfo PackageInfo for the package, containing the package signatures. 331 * @return Access status. 332 */ 333 public int getCarrierPrivilegeStatus(PackageInfo packageInfo) { 334 Signature[] signatures = packageInfo.signatures; 335 for (Signature sig : signatures) { 336 int accessStatus = getCarrierPrivilegeStatus(sig, packageInfo.packageName); 337 if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 338 return accessStatus; 339 } 340 } 341 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 342 } 343 344 /** 345 * Returns the status of the carrier privileges for the caller of the current transaction. 346 * 347 * @param packageManager PackageManager for getting signatures and package names. 348 * @return Access status. 349 */ 350 public int getCarrierPrivilegeStatusForCurrentTransaction(PackageManager packageManager) { 351 String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid()); 352 353 for (String pkg : packages) { 354 int accessStatus = getCarrierPrivilegeStatus(packageManager, pkg); 355 if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 356 return accessStatus; 357 } 358 } 359 return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 360 } 361 362 /** 363 * Returns the package name of the carrier app that should handle the input intent. 364 * 365 * @param packageManager PackageManager for getting receivers. 366 * @param intent Intent that will be sent. 367 * @return list of carrier app package names that can handle the intent. 368 * Returns null if there is an error and an empty list if there 369 * are no matching packages. 370 */ 371 public List<String> getCarrierPackageNamesForIntent( 372 PackageManager packageManager, Intent intent) { 373 List<String> packages = new ArrayList<String>(); 374 List<ResolveInfo> receivers = new ArrayList<ResolveInfo>(); 375 receivers.addAll(packageManager.queryBroadcastReceivers(intent, 0)); 376 receivers.addAll(packageManager.queryIntentContentProviders(intent, 0)); 377 receivers.addAll(packageManager.queryIntentActivities(intent, 0)); 378 receivers.addAll(packageManager.queryIntentServices(intent, 0)); 379 380 for (ResolveInfo resolveInfo : receivers) { 381 String packageName = getPackageName(resolveInfo); 382 if (packageName == null) { 383 continue; 384 } 385 386 int status = getCarrierPrivilegeStatus(packageManager, packageName); 387 if (status == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 388 packages.add(packageName); 389 } else if (status != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 390 // Any status apart from HAS_ACCESS and NO_ACCESS is considered an error. 391 return null; 392 } 393 } 394 395 return packages; 396 } 397 398 @Nullable 399 private String getPackageName(ResolveInfo resolveInfo) { 400 if (resolveInfo.activityInfo != null) { 401 return resolveInfo.activityInfo.packageName; 402 } else if (resolveInfo.serviceInfo != null) { 403 return resolveInfo.serviceInfo.packageName; 404 } else if (resolveInfo.providerInfo != null) { 405 return resolveInfo.providerInfo.packageName; 406 } 407 return null; 408 } 409 410 @Override 411 public void handleMessage(Message msg) { 412 AsyncResult ar; 413 414 switch (msg.what) { 415 416 case EVENT_OPEN_LOGICAL_CHANNEL_DONE: 417 log("EVENT_OPEN_LOGICAL_CHANNEL_DONE"); 418 ar = (AsyncResult) msg.obj; 419 if (ar.exception == null && ar.result != null) { 420 mChannelId = ((int[]) ar.result)[0]; 421 mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2, P3, 422 DATA, obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, 423 mChannelId)); 424 } else { 425 // MISSING_RESOURCE could be due to logical channels temporarily unavailable, 426 // so we retry up to MAX_RETRY times, with an interval of RETRY_INTERVAL_MS. 427 if (ar.exception instanceof CommandException && mRetryCount < MAX_RETRY 428 && ((CommandException) (ar.exception)).getCommandError() 429 == CommandException.Error.MISSING_RESOURCE) { 430 mRetryCount++; 431 removeCallbacks(mRetryRunnable); 432 postDelayed(mRetryRunnable, RETRY_INTERVAL_MS); 433 } else { 434 // if rules cannot be read from ARA applet, 435 // fallback to PKCS15-based ARF. 436 log("No ARA, try ARF next."); 437 mUiccPkcs15 = new UiccPkcs15(mUiccCard, 438 obtainMessage(EVENT_PKCS15_READ_DONE)); 439 } 440 } 441 break; 442 443 case EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE: 444 log("EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE"); 445 ar = (AsyncResult) msg.obj; 446 if (ar.exception == null && ar.result != null) { 447 IccIoResult response = (IccIoResult) ar.result; 448 if (response.sw1 == 0x90 && response.sw2 == 0x00 449 && response.payload != null && response.payload.length > 0) { 450 try { 451 mRules += IccUtils.bytesToHexString(response.payload) 452 .toUpperCase(Locale.US); 453 if (isDataComplete()) { 454 mAccessRules = parseRules(mRules); 455 updateState(STATE_LOADED, "Success!"); 456 } else { 457 mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, 458 P1, P2_EXTENDED_DATA, P3, DATA, 459 obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, 460 mChannelId)); 461 break; 462 } 463 } catch (IllegalArgumentException | IndexOutOfBoundsException ex) { 464 updateState(STATE_ERROR, "Error parsing rules: " + ex); 465 } 466 } else { 467 String errorMsg = "Invalid response: payload=" + response.payload 468 + " sw1=" + response.sw1 + " sw2=" + response.sw2; 469 updateState(STATE_ERROR, errorMsg); 470 } 471 } else { 472 updateState(STATE_ERROR, "Error reading value from SIM."); 473 } 474 475 mUiccCard.iccCloseLogicalChannel(mChannelId, obtainMessage( 476 EVENT_CLOSE_LOGICAL_CHANNEL_DONE)); 477 mChannelId = -1; 478 break; 479 480 case EVENT_CLOSE_LOGICAL_CHANNEL_DONE: 481 log("EVENT_CLOSE_LOGICAL_CHANNEL_DONE"); 482 break; 483 484 case EVENT_PKCS15_READ_DONE: 485 log("EVENT_PKCS15_READ_DONE"); 486 if (mUiccPkcs15 == null || mUiccPkcs15.getRules() == null) { 487 updateState(STATE_ERROR, "No ARA or ARF."); 488 } else { 489 for (String cert : mUiccPkcs15.getRules()) { 490 AccessRule accessRule = new AccessRule( 491 IccUtils.hexStringToBytes(cert), "", 0x00); 492 mAccessRules.add(accessRule); 493 } 494 updateState(STATE_LOADED, "Success!"); 495 } 496 break; 497 498 default: 499 Rlog.e(LOG_TAG, "Unknown event " + msg.what); 500 } 501 } 502 503 /* 504 * Check if all rule bytes have been read from UICC. 505 * For long payload, we need to fetch it repeatly before start parsing it. 506 */ 507 private boolean isDataComplete() { 508 log("isDataComplete mRules:" + mRules); 509 if (mRules.startsWith(TAG_ALL_REF_AR_DO)) { 510 TLV allRules = new TLV(TAG_ALL_REF_AR_DO); 511 String lengthBytes = allRules.parseLength(mRules); 512 log("isDataComplete lengthBytes: " + lengthBytes); 513 if (mRules.length() == TAG_ALL_REF_AR_DO.length() + lengthBytes.length() + 514 allRules.length) { 515 log("isDataComplete yes"); 516 return true; 517 } else { 518 log("isDataComplete no"); 519 return false; 520 } 521 } else { 522 throw new IllegalArgumentException("Tags don't match."); 523 } 524 } 525 526 /* 527 * Parses the rules from the input string. 528 */ 529 private static List<AccessRule> parseRules(String rules) { 530 log("Got rules: " + rules); 531 532 TLV allRefArDo = new TLV(TAG_ALL_REF_AR_DO); //FF40 533 allRefArDo.parse(rules, true); 534 535 String arDos = allRefArDo.value; 536 List<AccessRule> accessRules = new ArrayList<AccessRule>(); 537 while (!arDos.isEmpty()) { 538 TLV refArDo = new TLV(TAG_REF_AR_DO); //E2 539 arDos = refArDo.parse(arDos, false); 540 AccessRule accessRule = parseRefArdo(refArDo.value); 541 if (accessRule != null) { 542 accessRules.add(accessRule); 543 } else { 544 Rlog.e(LOG_TAG, "Skip unrecognized rule." + refArDo.value); 545 } 546 } 547 return accessRules; 548 } 549 550 /* 551 * Parses a single rule. 552 */ 553 private static AccessRule parseRefArdo(String rule) { 554 log("Got rule: " + rule); 555 556 String certificateHash = null; 557 String packageName = null; 558 String tmp = null; 559 long accessType = 0; 560 561 while (!rule.isEmpty()) { 562 if (rule.startsWith(TAG_REF_DO)) { 563 TLV refDo = new TLV(TAG_REF_DO); //E1 564 rule = refDo.parse(rule, false); 565 566 // Skip unrelated rules. 567 if (!refDo.value.startsWith(TAG_DEVICE_APP_ID_REF_DO)) { 568 return null; 569 } 570 571 TLV deviceDo = new TLV(TAG_DEVICE_APP_ID_REF_DO); //C1 572 tmp = deviceDo.parse(refDo.value, false); 573 certificateHash = deviceDo.value; 574 575 if (!tmp.isEmpty()) { 576 if (!tmp.startsWith(TAG_PKG_REF_DO)) { 577 return null; 578 } 579 TLV pkgDo = new TLV(TAG_PKG_REF_DO); //CA 580 pkgDo.parse(tmp, true); 581 packageName = new String(IccUtils.hexStringToBytes(pkgDo.value)); 582 } else { 583 packageName = null; 584 } 585 } else if (rule.startsWith(TAG_AR_DO)) { 586 TLV arDo = new TLV(TAG_AR_DO); //E3 587 rule = arDo.parse(rule, false); 588 589 // Skip unrelated rules. 590 if (!arDo.value.startsWith(TAG_PERM_AR_DO)) { 591 return null; 592 } 593 594 TLV permDo = new TLV(TAG_PERM_AR_DO); //DB 595 permDo.parse(arDo.value, true); 596 } else { 597 // Spec requires it must be either TAG_REF_DO or TAG_AR_DO. 598 throw new RuntimeException("Invalid Rule type"); 599 } 600 } 601 602 AccessRule accessRule = new AccessRule(IccUtils.hexStringToBytes(certificateHash), 603 packageName, accessType); 604 return accessRule; 605 } 606 607 /* 608 * Converts a Signature into a Certificate hash usable for comparison. 609 */ 610 private static byte[] getCertHash(Signature signature, String algo) { 611 try { 612 MessageDigest md = MessageDigest.getInstance(algo); 613 return md.digest(signature.toByteArray()); 614 } catch (NoSuchAlgorithmException ex) { 615 Rlog.e(LOG_TAG, "NoSuchAlgorithmException: " + ex); 616 } 617 return null; 618 } 619 620 /* 621 * Updates the state and notifies the UiccCard that the rules have finished loading. 622 */ 623 private void updateState(int newState, String statusMessage) { 624 mState.set(newState); 625 if (mLoadedCallback != null) { 626 mLoadedCallback.sendToTarget(); 627 } 628 629 mStatusMessage = statusMessage; 630 } 631 632 private static void log(String msg) { 633 if (DBG) Rlog.d(LOG_TAG, msg); 634 } 635 636 /** 637 * Dumps info to Dumpsys - useful for debugging. 638 */ 639 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 640 pw.println("UiccCarrierPrivilegeRules: " + this); 641 pw.println(" mState=" + getStateString(mState.get())); 642 pw.println(" mStatusMessage='" + mStatusMessage + "'"); 643 if (mAccessRules != null) { 644 pw.println(" mAccessRules: "); 645 for (AccessRule ar : mAccessRules) { 646 pw.println(" rule='" + ar + "'"); 647 } 648 } else { 649 pw.println(" mAccessRules: null"); 650 } 651 if (mUiccPkcs15 != null) { 652 pw.println(" mUiccPkcs15: " + mUiccPkcs15); 653 mUiccPkcs15.dump(fd, pw, args); 654 } else { 655 pw.println(" mUiccPkcs15: null"); 656 } 657 pw.flush(); 658 } 659 660 /* 661 * Converts state into human readable format. 662 */ 663 private String getStateString(int state) { 664 switch (state) { 665 case STATE_LOADING: 666 return "STATE_LOADING"; 667 case STATE_LOADED: 668 return "STATE_LOADED"; 669 case STATE_ERROR: 670 return "STATE_ERROR"; 671 default: 672 return "UNKNOWN"; 673 } 674 } 675 } 676