UiccCarrierPrivilegeRulespublic 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 boolean | areCarrierPriviligeRulesLoaded()Returns true if the carrier privilege rules have finished loading.
return mState.get() != STATE_LOADING;
| public void | dump(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.List | getCarrierPackageNamesForIntent(android.content.pm.PackageManager packageManager, android.content.Intent intent)Returns the package name of the carrier app that should handle the input intent.
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 int | getCarrierPrivilegeStatus(android.content.pm.Signature signature, java.lang.String packageName)Returns the status of the carrier privileges for the input certificate and package name.
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 int | getCarrierPrivilegeStatus(android.content.pm.PackageManager packageManager, java.lang.String packageName)Returns the status of the carrier privileges for the input package name.
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 int | getCarrierPrivilegeStatusForCurrentTransaction(android.content.pm.PackageManager packageManager)Returns the status of the carrier privileges for the caller of the current transaction.
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.String | getPackageName(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.String | getStateString(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 void | handleMessage(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 boolean | isDataComplete()
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$AccessRule | parseRefArdo(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.List | parseRules(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 void | updateState(int newState, java.lang.String statusMessage)
mState.set(newState);
if (mLoadedCallback != null) {
mLoadedCallback.sendToTarget();
}
mStatusMessage = statusMessage;
Rlog.e(LOG_TAG, mStatusMessage);
|
|