FileDocCategorySizeDatePackage
UiccCarrierPrivilegeRules.javaAPI DocAndroid 5.1 API23105Thu Mar 12 22:22:54 GMT 2015com.android.internal.telephony.uicc

UiccCarrierPrivilegeRules

public class UiccCarrierPrivilegeRules extends android.os.Handler
Class that reads and stores the carrier privileged rules from the UICC. The rules are read when the class is created, hence it should only be created after the UICC can be read. And it should be deleted when a UICC is changed. The spec for the rules: GP Secure Element Access Control: http://www.globalplatform.org/specifications/review/GPD_SE_Access_Control_v1.0.20.pdf Extension spec: https://code.google.com/p/seek-for-android/ TODO: Notifications. {@hide}

Fields Summary
private static final String
LOG_TAG
private static final String
AID
private static final int
CLA
private static final int
COMMAND
private static final int
P1
private static final int
P2
private static final int
P2_EXTENDED_DATA
private static final int
P3
private static final String
DATA
private static final String
TAG_ALL_REF_AR_DO
private static final String
TAG_REF_AR_DO
private static final String
TAG_REF_DO
private static final String
TAG_DEVICE_APP_ID_REF_DO
private static final String
TAG_PKG_REF_DO
private static final String
TAG_AR_DO
private static final String
TAG_PERM_AR_DO
private static final int
EVENT_OPEN_LOGICAL_CHANNEL_DONE
private static final int
EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE
private static final int
EVENT_CLOSE_LOGICAL_CHANNEL_DONE
private static final int
STATE_LOADING
private static final int
STATE_LOADED
private static final int
STATE_ERROR
private UiccCard
mUiccCard
private AtomicInteger
mState
private List
mAccessRules
private String
mRules
private android.os.Message
mLoadedCallback
private String
mStatusMessage
private int
mChannelId
Constructors Summary
public UiccCarrierPrivilegeRules(UiccCard uiccCard, android.os.Message loadedCallback)

        Rlog.d(LOG_TAG, "Creating UiccCarrierPrivilegeRules");
        mUiccCard = uiccCard;
        mState = new AtomicInteger(STATE_LOADING);
        mStatusMessage = "Not loaded.";
        mLoadedCallback = loadedCallback;
        mRules = "";

        // Start loading the rules.
        mUiccCard.iccOpenLogicalChannel(AID,
            obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, null));
    
Methods Summary
public booleanareCarrierPriviligeRulesLoaded()
Returns true if the carrier privilege rules have finished loading.

        return mState.get() != STATE_LOADING;
    
public voiddump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)
Dumps info to Dumpsys - useful for debugging.

        pw.println("UiccCarrierPrivilegeRules: " + this);
        pw.println(" mState=" + getStateString(mState.get()));
        pw.println(" mStatusMessage='" + mStatusMessage + "'");
        if (mAccessRules != null) {
            pw.println(" mAccessRules: ");
            for (AccessRule ar : mAccessRules) {
                pw.println("  rule='" + ar + "'");
            }
        } else {
            pw.println(" mAccessRules: null");
        }
        pw.flush();
    
public java.util.ListgetCarrierPackageNamesForIntent(android.content.pm.PackageManager packageManager, android.content.Intent intent)
Returns the package name of the carrier app that should handle the input intent.

param
packageManager PackageManager for getting receivers.
param
intent Intent that will be sent.
return
list of carrier app package names that can handle the intent. Returns null if there is an error and an empty list if there are no matching packages.

        List<String> packages = new ArrayList<String>();
        List<ResolveInfo> receivers = new ArrayList<ResolveInfo>();
        receivers.addAll(packageManager.queryBroadcastReceivers(intent, 0));
        receivers.addAll(packageManager.queryIntentContentProviders(intent, 0));
        receivers.addAll(packageManager.queryIntentActivities(intent, 0));
        receivers.addAll(packageManager.queryIntentServices(intent, 0));

        for (ResolveInfo resolveInfo : receivers) {
            String packageName = getPackageName(resolveInfo);
            if (packageName == null) {
                continue;
            }

            int status = getCarrierPrivilegeStatus(packageManager, packageName);
            if (status == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
                packages.add(packageName);
            } else if (status != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
                // Any status apart from HAS_ACCESS and NO_ACCESS is considered an error.
                return null;
            }
        }

        return packages;
    
public intgetCarrierPrivilegeStatus(android.content.pm.Signature signature, java.lang.String packageName)
Returns the status of the carrier privileges for the input certificate and package name.

param
signature The signature of the certificate.
param
packageName name of the package.
return
Access status.

        Rlog.d(LOG_TAG, "hasCarrierPrivileges: " + signature + " : " + packageName);
        int state = mState.get();
        if (state == STATE_LOADING) {
            Rlog.d(LOG_TAG, "Rules not loaded.");
            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
        } else if (state == STATE_ERROR) {
            Rlog.d(LOG_TAG, "Error loading rules.");
            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES;
        }

        // SHA-1 is for backward compatible support only, strongly discouraged for new use.
        byte[] certHash = getCertHash(signature, "SHA-1");
        byte[] certHash256 = getCertHash(signature, "SHA-256");
        Rlog.d(LOG_TAG, "Checking SHA1: " + IccUtils.bytesToHexString(certHash) + " : " + packageName);
        Rlog.d(LOG_TAG, "Checking SHA256: " + IccUtils.bytesToHexString(certHash256) + " : " + packageName);
        for (AccessRule ar : mAccessRules) {
            if (ar.matches(certHash, packageName) || ar.matches(certHash256, packageName)) {
                Rlog.d(LOG_TAG, "Match found!");
                return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
            }
        }

        Rlog.d(LOG_TAG, "No matching rule found. Returning false.");
        return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
    
public intgetCarrierPrivilegeStatus(android.content.pm.PackageManager packageManager, java.lang.String packageName)
Returns the status of the carrier privileges for the input package name.

param
packageManager PackageManager for getting signatures.
param
packageName name of the package.
return
Access status.

        try {
            PackageInfo pInfo = packageManager.getPackageInfo(packageName,
                PackageManager.GET_SIGNATURES);
            Signature[] signatures = pInfo.signatures;
            for (Signature sig : signatures) {
                int accessStatus = getCarrierPrivilegeStatus(sig, pInfo.packageName);
                if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
                    return accessStatus;
                }
            }
        } catch (PackageManager.NameNotFoundException ex) {
            Rlog.e(LOG_TAG, "NameNotFoundException", ex);
        }
        return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
    
public intgetCarrierPrivilegeStatusForCurrentTransaction(android.content.pm.PackageManager packageManager)
Returns the status of the carrier privileges for the caller of the current transaction.

param
packageManager PackageManager for getting signatures and package names.
return
Access status.

        String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid());

        for (String pkg : packages) {
            int accessStatus = getCarrierPrivilegeStatus(packageManager, pkg);
            if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) {
                return accessStatus;
            }
        }
        return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
    
private static byte[]getCertHash(android.content.pm.Signature signature, java.lang.String algo)

        try {
            MessageDigest md = MessageDigest.getInstance(algo);
            return md.digest(signature.toByteArray());
        } catch (NoSuchAlgorithmException ex) {
            Rlog.e(LOG_TAG, "NoSuchAlgorithmException: " + ex);
        }
        return null;
    
private java.lang.StringgetPackageName(android.content.pm.ResolveInfo resolveInfo)

        if (resolveInfo.activityInfo != null) {
            return resolveInfo.activityInfo.packageName;
        } else if (resolveInfo.serviceInfo != null) {
            return resolveInfo.serviceInfo.packageName;
        } else if (resolveInfo.providerInfo != null) {
            return resolveInfo.providerInfo.packageName;
        }
        return null;
    
private java.lang.StringgetStateString(int state)

      switch (state) {
        case STATE_LOADING:
            return "STATE_LOADING";
        case STATE_LOADED:
            return "STATE_LOADED";
        case STATE_ERROR:
            return "STATE_ERROR";
        default:
            return "UNKNOWN";
      }
    
public voidhandleMessage(android.os.Message msg)

        AsyncResult ar;

        switch (msg.what) {

          case EVENT_OPEN_LOGICAL_CHANNEL_DONE:
              Rlog.d(LOG_TAG, "EVENT_OPEN_LOGICAL_CHANNEL_DONE");
              ar = (AsyncResult) msg.obj;
              if (ar.exception == null && ar.result != null) {
                  mChannelId = ((int[]) ar.result)[0];
                  mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2, P3, DATA,
                      obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(mChannelId)));
              } else {
                  updateState(STATE_ERROR, "Error opening channel");
              }
              break;

          case EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE:
              Rlog.d(LOG_TAG, "EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE");
              ar = (AsyncResult) msg.obj;
              if (ar.exception == null && ar.result != null) {
                  IccIoResult response = (IccIoResult) ar.result;
                  if (response.sw1 == 0x90 && response.sw2 == 0x00 &&
                      response.payload != null && response.payload.length > 0) {
                      try {
                          mRules += IccUtils.bytesToHexString(response.payload).toUpperCase(Locale.US);
                          if (isDataComplete()) {
                              mAccessRules = parseRules(mRules);
                              updateState(STATE_LOADED, "Success!");
                          } else {
                              mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2_EXTENDED_DATA, P3, DATA,
                                  obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(mChannelId)));
                              break;
                          }
                      } catch (IllegalArgumentException ex) {
                          updateState(STATE_ERROR, "Error parsing rules: " + ex);
                      } catch (IndexOutOfBoundsException ex) {
                          updateState(STATE_ERROR, "Error parsing rules: " + ex);
                      }
                   } else {
                      String errorMsg = "Invalid response: payload=" + response.payload +
                              " sw1=" + response.sw1 + " sw2=" + response.sw2;
                      updateState(STATE_ERROR, errorMsg);
                   }
              } else {
                  updateState(STATE_ERROR, "Error reading value from SIM.");
              }

              mUiccCard.iccCloseLogicalChannel(mChannelId, obtainMessage(
                      EVENT_CLOSE_LOGICAL_CHANNEL_DONE));
              mChannelId = -1;
              break;

          case EVENT_CLOSE_LOGICAL_CHANNEL_DONE:
              Rlog.d(LOG_TAG, "EVENT_CLOSE_LOGICAL_CHANNEL_DONE");
              break;

          default:
              Rlog.e(LOG_TAG, "Unknown event " + msg.what);
        }
    
private booleanisDataComplete()

        Rlog.d(LOG_TAG, "isDataComplete mRules:" + mRules);
        if (mRules.startsWith(TAG_ALL_REF_AR_DO)) {
            TLV allRules = new TLV(TAG_ALL_REF_AR_DO);
            String lengthBytes = allRules.parseLength(mRules);
            Rlog.d(LOG_TAG, "isDataComplete lengthBytes: " + lengthBytes);
            if (mRules.length() == TAG_ALL_REF_AR_DO.length() + lengthBytes.length() +
                                   allRules.length) {
                Rlog.d(LOG_TAG, "isDataComplete yes");
                return true;
            } else {
                Rlog.d(LOG_TAG, "isDataComplete no");
                return false;
            }
        } else {
            throw new IllegalArgumentException("Tags don't match.");
        }
    
private static com.android.internal.telephony.uicc.UiccCarrierPrivilegeRules$AccessRuleparseRefArdo(java.lang.String rule)

        Rlog.d(LOG_TAG, "Got rule: " + rule);

        String certificateHash = null;
        String packageName = null;
        String tmp = null;
        long accessType = 0;

        while (!rule.isEmpty()) {
            if (rule.startsWith(TAG_REF_DO)) {
                TLV refDo = new TLV(TAG_REF_DO); //E1
                rule = refDo.parse(rule, false);

                // Skip unrelated rules.
                if (!refDo.value.startsWith(TAG_DEVICE_APP_ID_REF_DO)) {
                    return null;
                }

                TLV deviceDo = new TLV(TAG_DEVICE_APP_ID_REF_DO); //C1
                tmp = deviceDo.parse(refDo.value, false);
                certificateHash = deviceDo.value;

                if (!tmp.isEmpty()) {
                  if (!tmp.startsWith(TAG_PKG_REF_DO)) {
                      return null;
                  }
                  TLV pkgDo = new TLV(TAG_PKG_REF_DO); //CA
                  pkgDo.parse(tmp, true);
                  packageName = new String(IccUtils.hexStringToBytes(pkgDo.value));
                } else {
                  packageName = null;
                }
            } else if (rule.startsWith(TAG_AR_DO)) {
                TLV arDo = new TLV(TAG_AR_DO); //E3
                rule = arDo.parse(rule, false);

                // Skip unrelated rules.
                if (!arDo.value.startsWith(TAG_PERM_AR_DO)) {
                    return null;
                }

                TLV permDo = new TLV(TAG_PERM_AR_DO); //DB
                permDo.parse(arDo.value, true);
                Rlog.e(LOG_TAG, permDo.value);
            } else  {
                // Spec requires it must be either TAG_REF_DO or TAG_AR_DO.
                throw new RuntimeException("Invalid Rule type");
            }
        }

        Rlog.e(LOG_TAG, "Adding: " + certificateHash + " : " + packageName + " : " + accessType);

        AccessRule accessRule = new AccessRule(IccUtils.hexStringToBytes(certificateHash),
            packageName, accessType);
        Rlog.e(LOG_TAG, "Parsed rule: " + accessRule);
        return accessRule;
    
private static java.util.ListparseRules(java.lang.String rules)

        Rlog.d(LOG_TAG, "Got rules: " + rules);

        TLV allRefArDo = new TLV(TAG_ALL_REF_AR_DO); //FF40
        allRefArDo.parse(rules, true);

        String arDos = allRefArDo.value;
        List<AccessRule> accessRules = new ArrayList<AccessRule>();
        while (!arDos.isEmpty()) {
            TLV refArDo = new TLV(TAG_REF_AR_DO); //E2
            arDos = refArDo.parse(arDos, false);
            AccessRule accessRule = parseRefArdo(refArDo.value);
            if (accessRule != null) {
                accessRules.add(accessRule);
            } else {
              Rlog.e(LOG_TAG, "Skip unrecognized rule." + refArDo.value);
            }
        }
        return accessRules;
    
private voidupdateState(int newState, java.lang.String statusMessage)

        mState.set(newState);
        if (mLoadedCallback != null) {
            mLoadedCallback.sendToTarget();
        }

        mStatusMessage = statusMessage;
        Rlog.e(LOG_TAG, mStatusMessage);