UiccCarrierPrivilegeRules.java revision b757d07125d8294062586b5258e4e79d0b8417a3
14baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal/* 24baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Copyright (C) 2014 The Android Open Source Project 34baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * 44baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Licensed under the Apache License, Version 2.0 (the "License"); 54baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * you may not use this file except in compliance with the License. 64baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * You may obtain a copy of the License at 74baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * 84baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * http://www.apache.org/licenses/LICENSE-2.0 94baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * 104baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Unless required by applicable law or agreed to in writing, software 114baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * distributed under the License is distributed on an "AS IS" BASIS, 124baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * See the License for the specific language governing permissions and 144baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * limitations under the License. 154baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal */ 164baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 174baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalpackage com.android.internal.telephony.uicc; 184baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 19ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastryimport android.annotation.Nullable; 20c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawalimport android.content.Intent; 21c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawalimport android.content.pm.PackageInfo; 22c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawalimport android.content.pm.PackageManager; 23c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawalimport android.content.pm.ResolveInfo; 244baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.content.pm.Signature; 254baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.os.AsyncResult; 26c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawalimport android.os.Binder; 274baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.os.Handler; 284baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.os.Message; 294baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.telephony.Rlog; 304baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport android.telephony.TelephonyManager; 314baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 32b757d07125d8294062586b5258e4e79d0b8417a3Junda Liuimport com.android.internal.telephony.CommandException; 334baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport com.android.internal.telephony.CommandsInterface; 344baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport com.android.internal.telephony.uicc.IccUtils; 354baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 364baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.io.ByteArrayInputStream; 3738aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawalimport java.io.FileDescriptor; 3838aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawalimport java.io.PrintWriter; 394baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.lang.IllegalArgumentException; 407541d468b7d9464008d6186bc7c1bcef1c925782Junda Liuimport java.lang.IndexOutOfBoundsException; 414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.MessageDigest; 424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.NoSuchAlgorithmException; 434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.cert.Certificate; 444baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.cert.CertificateException; 454baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.cert.CertificateFactory; 464baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.security.cert.X509Certificate; 474baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.util.ArrayList; 484baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.util.Arrays; 494baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.util.List; 504baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalimport java.util.Locale; 517f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawalimport java.util.concurrent.atomic.AtomicInteger; 524baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 534baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal/** 544baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Class that reads and stores the carrier privileged rules from the UICC. 554baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * 564baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * The rules are read when the class is created, hence it should only be created 574baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * after the UICC can be read. And it should be deleted when a UICC is changed. 584baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * 594baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * The spec for the rules: 60e5b5f10d2d09f62c265381cab0816edfbdf566f0Junda Liu * GP Secure Element Access Control: 61e5b5f10d2d09f62c265381cab0816edfbdf566f0Junda Liu * http://www.globalplatform.org/specifications/review/GPD_SE_Access_Control_v1.0.20.pdf 62e5b5f10d2d09f62c265381cab0816edfbdf566f0Junda Liu * Extension spec: 63e5b5f10d2d09f62c265381cab0816edfbdf566f0Junda Liu * https://code.google.com/p/seek-for-android/ 644baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * 654baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * 664baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * TODO: Notifications. 674baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * 684baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * {@hide} 694baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal */ 704baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawalpublic class UiccCarrierPrivilegeRules extends Handler { 714baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final String LOG_TAG = "UiccCarrierPrivilegeRules"; 724baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 73e5b5f10d2d09f62c265381cab0816edfbdf566f0Junda Liu private static final String AID = "A00000015141434C00"; 744baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final int CLA = 0x80; 757b122b5ef07eca751ca8b6938562737d6e3de2c8Shishir Agrawal private static final int COMMAND = 0xCA; 767b122b5ef07eca751ca8b6938562737d6e3de2c8Shishir Agrawal private static final int P1 = 0xFF; 777b122b5ef07eca751ca8b6938562737d6e3de2c8Shishir Agrawal private static final int P2 = 0x40; 787541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu private static final int P2_EXTENDED_DATA = 0x60; 794baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final int P3 = 0x00; 804baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final String DATA = ""; 814baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 82004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu /* 83004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * Rules format: 84004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * ALL_REF_AR_DO = TAG_ALL_REF_AR_DO + len + [REF_AR_DO]*n 85004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * REF_AR_DO = TAG_REF_AR_DO + len + REF-DO + AR-DO 86004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * 87004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * REF_DO = TAG_REF_DO + len + DEVICE_APP_ID_REF_DO + (optional) PKG_REF_DO 88004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * AR_DO = TAG_AR_DO + len + PERM_AR_DO 89004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * 90c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu * DEVICE_APP_ID_REF_DO = TAG_DEVICE_APP_ID_REF_DO + len + sha256 hexstring of cert 91004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * PKG_REF_DO = TAG_PKG_REF_DO + len + package name 92004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * PERM_AR_DO = TAG_PERM_AR_DO + len + detailed permission (8 bytes) 93004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * 94004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * Data objects hierarchy by TAG: 95004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * FF40 96004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * E2 97004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * E1 98004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * C1 99004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * CA 100004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * E3 101004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu * DB 102004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu */ 1034baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal // Values from the data standard. 1044baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final String TAG_ALL_REF_AR_DO = "FF40"; 1054baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final String TAG_REF_AR_DO = "E2"; 1064baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final String TAG_REF_DO = "E1"; 1074baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final String TAG_DEVICE_APP_ID_REF_DO = "C1"; 1084baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final String TAG_PKG_REF_DO = "CA"; 109004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu private static final String TAG_AR_DO = "E3"; 110004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu private static final String TAG_PERM_AR_DO = "DB"; 1114baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 1124baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 1; 1134baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final int EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE = 2; 1144baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final int EVENT_CLOSE_LOGICAL_CHANNEL_DONE = 3; 1154baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 1164baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal // State of the object. 1174baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final int STATE_LOADING = 0; 1184baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final int STATE_LOADED = 1; 1194baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static final int STATE_ERROR = 2; 1204baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 121b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu // Max number of retries for open logical channel, interval is 10s. 122b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu private static final int MAX_RETRY = 3; 123b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu private static final int RETRY_INTERVAL_MS = 10000; 124b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu 1254baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal // Describes a single rule. 1264baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static class AccessRule { 1274baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal public byte[] certificateHash; 1284baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal public String packageName; 1294baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal public long accessType; // This bit is not currently used, but reserved for future use. 1304baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 1314baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal AccessRule(byte[] certificateHash, String packageName, long accessType) { 1324baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal this.certificateHash = certificateHash; 1334baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal this.packageName = packageName; 1344baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal this.accessType = accessType; 1354baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 1364baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 1374baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal boolean matches(byte[] certHash, String packageName) { 1384baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal return certHash != null && Arrays.equals(this.certificateHash, certHash) && 1394baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal (this.packageName == null || this.packageName.equals(packageName)); 1404baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 1414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 1424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal @Override 1434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal public String toString() { 14438aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal return "cert: " + IccUtils.bytesToHexString(certificateHash) + " pkg: " + 14538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal packageName + " access: " + accessType; 1464baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 1474baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 1484baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 1494baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal // Used for parsing the data from the UICC. 1504baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static class TLV { 1517541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu private static final int SINGLE_BYTE_MAX_LENGTH = 0x80; 1524baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private String tag; 1537541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu // Length encoding is in GPC_Specification_2.2.1: 11.1.5 APDU Message and Data Length. 1547541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu // Length field could be either 1 byte if length < 128, or multiple bytes with first byte 1557541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu // specifying how many bytes are used for length, followed by length bytes. 1567541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu // Bytes for the length field, in ASCII HEX string form. 1577541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu private String lengthBytes; 1587541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu // Decoded length as integer. 1594baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private Integer length; 1604baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private String value; 1614baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 1624baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal public TLV(String tag) { 1634baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal this.tag = tag; 1644baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 1654baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 1667541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu public String parseLength(String data) { 1677541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu int offset = tag.length(); 1687541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu int firstByte = Integer.parseInt(data.substring(offset, offset + 2), 16); 16964e02b05d7334a9d5704ee2b9f4710a310d9937eIan Pedowitz if (firstByte < SINGLE_BYTE_MAX_LENGTH) { 1707541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu length = firstByte * 2; 1717541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu lengthBytes = data.substring(offset, offset + 2); 1727541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } else { 1737541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu int numBytes = firstByte - SINGLE_BYTE_MAX_LENGTH; 1747541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu length = Integer.parseInt(data.substring(offset + 2, offset + 2 + numBytes * 2), 16) * 2; 1757541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu lengthBytes = data.substring(offset, offset + 2 + numBytes * 2); 1767541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } 1777541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu Rlog.d(LOG_TAG, "TLV parseLength length=" + length + "lenghtBytes: " + lengthBytes); 1787541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu return lengthBytes; 1797541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } 1807541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu 1814baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal public String parse(String data, boolean shouldConsumeAll) { 182004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu Rlog.d(LOG_TAG, "Parse TLV: " + tag); 1834baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal if (!data.startsWith(tag)) { 1844baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal throw new IllegalArgumentException("Tags don't match."); 1854baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 1864baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal int index = tag.length(); 1874baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal if (index + 2 > data.length()) { 1884baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal throw new IllegalArgumentException("No length."); 1894baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 1904baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 1917541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu parseLength(data); 1927541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu index += lengthBytes.length(); 1937541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu 1947541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu Rlog.d(LOG_TAG, "index="+index+" length="+length+"data.length="+data.length()); 1954baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal int remainingLength = data.length() - (index + length); 1964baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal if (remainingLength < 0) { 1974baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal throw new IllegalArgumentException("Not enough data."); 1984baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 1994baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal if (shouldConsumeAll && (remainingLength != 0)) { 2004baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal throw new IllegalArgumentException("Did not consume all."); 2014baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 2024baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal value = data.substring(index, index + length); 2034baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 204004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu Rlog.d(LOG_TAG, "Got TLV: " + tag + "," + length + "," + value); 2054baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 2064baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal return data.substring(index + length); 2074baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 2084baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 2094baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 2104baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private UiccCard mUiccCard; // Parent 2114baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private AtomicInteger mState; 2124baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private List<AccessRule> mAccessRules; 2137541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu private String mRules; 214c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal private Message mLoadedCallback; 21538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal private String mStatusMessage; // Only used for debugging. 2167541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu private int mChannelId; // Channel Id for communicating with UICC. 217b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu private int mRetryCount; // Number of retries for open logical channel. 218b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu private final Runnable mRetryRunnable = new Runnable() { 219b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu @Override 220b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu public void run() { 221b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu openChannel(); 222b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu } 223b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu }; 224b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu 225b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu private void openChannel() { 226b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu // Send open logical channel request. 227b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu mUiccCard.iccOpenLogicalChannel(AID, 228b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, null)); 229b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu } 2304baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 231c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal public UiccCarrierPrivilegeRules(UiccCard uiccCard, Message loadedCallback) { 2324baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.d(LOG_TAG, "Creating UiccCarrierPrivilegeRules"); 2334baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal mUiccCard = uiccCard; 2344baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal mState = new AtomicInteger(STATE_LOADING); 23538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal mStatusMessage = "Not loaded."; 236c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal mLoadedCallback = loadedCallback; 2377541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu mRules = ""; 2384baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 239b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu openChannel(); 2404baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 2414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 2424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal /** 243c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal * Returns true if the carrier privilege rules have finished loading. 244c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal */ 245c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal public boolean areCarrierPriviligeRulesLoaded() { 246c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal return mState.get() != STATE_LOADING; 247c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal } 248c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal 249c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal /** 250c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * Returns the status of the carrier privileges for the input certificate and package name. 2514baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * 2524baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * @param signature The signature of the certificate. 2534baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * @param packageName name of the package. 2544baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * @return Access status. 2554baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal */ 256c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal public int getCarrierPrivilegeStatus(Signature signature, String packageName) { 2574baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.d(LOG_TAG, "hasCarrierPrivileges: " + signature + " : " + packageName); 2584baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal int state = mState.get(); 2594baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal if (state == STATE_LOADING) { 2604baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.d(LOG_TAG, "Rules not loaded."); 2614baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED; 2624baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } else if (state == STATE_ERROR) { 2634baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.d(LOG_TAG, "Error loading rules."); 2644baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal return TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES; 2654baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 2664baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 267c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu // SHA-1 is for backward compatible support only, strongly discouraged for new use. 268c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu byte[] certHash = getCertHash(signature, "SHA-1"); 269c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu byte[] certHash256 = getCertHash(signature, "SHA-256"); 270c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu Rlog.d(LOG_TAG, "Checking SHA1: " + IccUtils.bytesToHexString(certHash) + " : " + packageName); 271c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu Rlog.d(LOG_TAG, "Checking SHA256: " + IccUtils.bytesToHexString(certHash256) + " : " + packageName); 2724baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal for (AccessRule ar : mAccessRules) { 273c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu if (ar.matches(certHash, packageName) || ar.matches(certHash256, packageName)) { 274004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu Rlog.d(LOG_TAG, "Match found!"); 2754baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 2764baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 2774baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 2784baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 2794baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.d(LOG_TAG, "No matching rule found. Returning false."); 2804baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 2814baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 2824baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 283c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal /** 284c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * Returns the status of the carrier privileges for the input package name. 285c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * 286c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * @param packageManager PackageManager for getting signatures. 287c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * @param packageName name of the package. 288c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * @return Access status. 289c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal */ 290c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal public int getCarrierPrivilegeStatus(PackageManager packageManager, String packageName) { 291c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal try { 292c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal PackageInfo pInfo = packageManager.getPackageInfo(packageName, 293c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal PackageManager.GET_SIGNATURES); 294c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal Signature[] signatures = pInfo.signatures; 295c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal for (Signature sig : signatures) { 296c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal int accessStatus = getCarrierPrivilegeStatus(sig, pInfo.packageName); 297c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 298c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal return accessStatus; 299c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 300c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 301c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } catch (PackageManager.NameNotFoundException ex) { 302c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal Rlog.e(LOG_TAG, "NameNotFoundException", ex); 303c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 304c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 305c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 306c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal 307c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal /** 308c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * Returns the status of the carrier privileges for the caller of the current transaction. 309c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * 310c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * @param packageManager PackageManager for getting signatures and package names. 311c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * @return Access status. 312c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal */ 313c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal public int getCarrierPrivilegeStatusForCurrentTransaction(PackageManager packageManager) { 314c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal String[] packages = packageManager.getPackagesForUid(Binder.getCallingUid()); 315c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal 316c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal for (String pkg : packages) { 317c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal int accessStatus = getCarrierPrivilegeStatus(packageManager, pkg); 318c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal if (accessStatus != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 319c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal return accessStatus; 320c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 321c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 322c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; 323c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 324c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal 325c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal /** 3267f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal * Returns the package name of the carrier app that should handle the input intent. 327c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * 328c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal * @param packageManager PackageManager for getting receivers. 329934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero * @param intent Intent that will be sent. 3307f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal * @return list of carrier app package names that can handle the intent. 3317f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal * Returns null if there is an error and an empty list if there 3327f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal * are no matching packages. 333c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal */ 334934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero public List<String> getCarrierPackageNamesForIntent( 335c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal PackageManager packageManager, Intent intent) { 3367f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal List<String> packages = new ArrayList<String>(); 337934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero List<ResolveInfo> receivers = new ArrayList<ResolveInfo>(); 338934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero receivers.addAll(packageManager.queryBroadcastReceivers(intent, 0)); 339934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero receivers.addAll(packageManager.queryIntentContentProviders(intent, 0)); 340934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero receivers.addAll(packageManager.queryIntentActivities(intent, 0)); 341934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero receivers.addAll(packageManager.queryIntentServices(intent, 0)); 342934a24a6aa2b7a981e872fa350648904ed80280aDiego Pontoriero 343c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal for (ResolveInfo resolveInfo : receivers) { 344ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry String packageName = getPackageName(resolveInfo); 345ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry if (packageName == null) { 346c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal continue; 347c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 348ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry 3497f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal int status = getCarrierPrivilegeStatus(packageManager, packageName); 3507f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal if (status == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 3517f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal packages.add(packageName); 3527f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal } else if (status != TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS) { 3537f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal // Any status apart from HAS_ACCESS and NO_ACCESS is considered an error. 3547f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal return null; 355c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 356c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 357c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal 3587f1a3f0ab65c144fde56e1246c5747b0c555034aShishir Agrawal return packages; 359c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal } 360c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal 361ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry @Nullable 362ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry private String getPackageName(ResolveInfo resolveInfo) { 363ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry if (resolveInfo.activityInfo != null) { 364ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry return resolveInfo.activityInfo.packageName; 365ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry } else if (resolveInfo.serviceInfo != null) { 366ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry return resolveInfo.serviceInfo.packageName; 367ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry } else if (resolveInfo.providerInfo != null) { 368ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry return resolveInfo.providerInfo.packageName; 369ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry } 370ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry return null; 371ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry } 372ed0cfa93b9e42486bfc7caeca83ceae1a2f7328eAbhijith Shastry 3734baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal @Override 3744baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal public void handleMessage(Message msg) { 3754baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal AsyncResult ar; 3764baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 3774baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal switch (msg.what) { 3784baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 3794baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal case EVENT_OPEN_LOGICAL_CHANNEL_DONE: 3804baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.d(LOG_TAG, "EVENT_OPEN_LOGICAL_CHANNEL_DONE"); 3814baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal ar = (AsyncResult) msg.obj; 3824baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal if (ar.exception == null && ar.result != null) { 3837541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu mChannelId = ((int[]) ar.result)[0]; 3847541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2, P3, DATA, 3857541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(mChannelId))); 3864baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } else { 387b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu // MISSING_RESOURCE could be due to logical channels temporarily unavailable, 388b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu // so we retry up to MAX_RETRY times, with an interval of RETRY_INTERVAL_MS. 389b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu if (ar.exception instanceof CommandException && mRetryCount < MAX_RETRY && 390b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu ((CommandException) (ar.exception)).getCommandError() == 391b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu CommandException.Error.MISSING_RESOURCE) { 392b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu mRetryCount++; 393b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu removeCallbacks(mRetryRunnable); 394b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu postDelayed(mRetryRunnable, RETRY_INTERVAL_MS); 395b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu } else { 396b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu updateState(STATE_ERROR, "Error opening channel: " + ar.exception); 397b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu } 3984baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 3994baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal break; 4004baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 4014baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal case EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE: 4024baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.d(LOG_TAG, "EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE"); 4034baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal ar = (AsyncResult) msg.obj; 4044baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal if (ar.exception == null && ar.result != null) { 4054baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal IccIoResult response = (IccIoResult) ar.result; 4067541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu if (response.sw1 == 0x90 && response.sw2 == 0x00 && 4077541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu response.payload != null && response.payload.length > 0) { 4084baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal try { 4097541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu mRules += IccUtils.bytesToHexString(response.payload).toUpperCase(Locale.US); 4107541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu if (isDataComplete()) { 4117541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu mAccessRules = parseRules(mRules); 4127541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu updateState(STATE_LOADED, "Success!"); 4137541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } else { 4147541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2_EXTENDED_DATA, P3, DATA, 4157541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(mChannelId))); 4167541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu break; 4177541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } 4184baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } catch (IllegalArgumentException ex) { 41938aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal updateState(STATE_ERROR, "Error parsing rules: " + ex); 4207541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } catch (IndexOutOfBoundsException ex) { 4217541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu updateState(STATE_ERROR, "Error parsing rules: " + ex); 4224baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 4234baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } else { 42438aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal String errorMsg = "Invalid response: payload=" + response.payload + 42538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal " sw1=" + response.sw1 + " sw2=" + response.sw2; 42638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal updateState(STATE_ERROR, errorMsg); 4274baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 4284baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } else { 42938aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal updateState(STATE_ERROR, "Error reading value from SIM."); 4304baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 4314baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 4327541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu mUiccCard.iccCloseLogicalChannel(mChannelId, obtainMessage( 4334baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal EVENT_CLOSE_LOGICAL_CHANNEL_DONE)); 4347541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu mChannelId = -1; 4354baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal break; 4364baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 4374baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal case EVENT_CLOSE_LOGICAL_CHANNEL_DONE: 4384baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.d(LOG_TAG, "EVENT_CLOSE_LOGICAL_CHANNEL_DONE"); 4394baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal break; 4404baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 4414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal default: 4424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.e(LOG_TAG, "Unknown event " + msg.what); 4434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 4444baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 4454baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 4464baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal /* 4477541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu * Check if all rule bytes have been read from UICC. 4487541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu * For long payload, we need to fetch it repeatly before start parsing it. 4497541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu */ 4507541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu private boolean isDataComplete() { 4517541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu Rlog.d(LOG_TAG, "isDataComplete mRules:" + mRules); 4527541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu if (mRules.startsWith(TAG_ALL_REF_AR_DO)) { 4537541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu TLV allRules = new TLV(TAG_ALL_REF_AR_DO); 4547541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu String lengthBytes = allRules.parseLength(mRules); 4557541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu Rlog.d(LOG_TAG, "isDataComplete lengthBytes: " + lengthBytes); 4567541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu if (mRules.length() == TAG_ALL_REF_AR_DO.length() + lengthBytes.length() + 4577541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu allRules.length) { 4587541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu Rlog.d(LOG_TAG, "isDataComplete yes"); 4597541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu return true; 4607541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } else { 4617541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu Rlog.d(LOG_TAG, "isDataComplete no"); 4627541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu return false; 4637541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } 4647541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } else { 4657541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu throw new IllegalArgumentException("Tags don't match."); 4667541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } 4677541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu } 4687541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu 4697541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu /* 4704baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Parses the rules from the input string. 4714baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal */ 4724baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static List<AccessRule> parseRules(String rules) { 4734baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.d(LOG_TAG, "Got rules: " + rules); 4744baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 475004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu TLV allRefArDo = new TLV(TAG_ALL_REF_AR_DO); //FF40 4764baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal allRefArDo.parse(rules, true); 4774baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 4784baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal String arDos = allRefArDo.value; 4794baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal List<AccessRule> accessRules = new ArrayList<AccessRule>(); 4804baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal while (!arDos.isEmpty()) { 481004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu TLV refArDo = new TLV(TAG_REF_AR_DO); //E2 4824baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal arDos = refArDo.parse(arDos, false); 48332bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu AccessRule accessRule = parseRefArdo(refArDo.value); 48432bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu if (accessRule != null) { 48532bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu accessRules.add(accessRule); 48632bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu } else { 48732bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu Rlog.e(LOG_TAG, "Skip unrecognized rule." + refArDo.value); 48832bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu } 4894baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 4904baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal return accessRules; 4914baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 4924baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 4934baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal /* 4944baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Parses a single rule. 4954baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal */ 4964baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal private static AccessRule parseRefArdo(String rule) { 4974baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.d(LOG_TAG, "Got rule: " + rule); 4984baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 4994baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal String certificateHash = null; 5004baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal String packageName = null; 501004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu String tmp = null; 5024baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal long accessType = 0; 5034baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 5044baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal while (!rule.isEmpty()) { 5054baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal if (rule.startsWith(TAG_REF_DO)) { 506004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu TLV refDo = new TLV(TAG_REF_DO); //E1 5074baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal rule = refDo.parse(rule, false); 5084baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 50932bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu // Skip unrelated rules. 51032bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu if (!refDo.value.startsWith(TAG_DEVICE_APP_ID_REF_DO)) { 51132bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu return null; 51232bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu } 51332bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu 514004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu TLV deviceDo = new TLV(TAG_DEVICE_APP_ID_REF_DO); //C1 515004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu tmp = deviceDo.parse(refDo.value, false); 516004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu certificateHash = deviceDo.value; 517004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu 518004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu if (!tmp.isEmpty()) { 51932bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu if (!tmp.startsWith(TAG_PKG_REF_DO)) { 52032bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu return null; 52132bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu } 522004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu TLV pkgDo = new TLV(TAG_PKG_REF_DO); //CA 523004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu pkgDo.parse(tmp, true); 524004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu packageName = new String(IccUtils.hexStringToBytes(pkgDo.value)); 5254baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } else { 526004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu packageName = null; 5274baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 5284baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } else if (rule.startsWith(TAG_AR_DO)) { 529004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu TLV arDo = new TLV(TAG_AR_DO); //E3 5304baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal rule = arDo.parse(rule, false); 5314baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 53232bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu // Skip unrelated rules. 53332bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu if (!arDo.value.startsWith(TAG_PERM_AR_DO)) { 53432bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu return null; 53532bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu } 53632bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu 537004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu TLV permDo = new TLV(TAG_PERM_AR_DO); //DB 5384baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal permDo.parse(arDo.value, true); 5394baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.e(LOG_TAG, permDo.value); 5404baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } else { 54132bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu // Spec requires it must be either TAG_REF_DO or TAG_AR_DO. 5424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal throw new RuntimeException("Invalid Rule type"); 5434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 5444baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 5454baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 5464baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.e(LOG_TAG, "Adding: " + certificateHash + " : " + packageName + " : " + accessType); 5474baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 5484baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal AccessRule accessRule = new AccessRule(IccUtils.hexStringToBytes(certificateHash), 5494baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal packageName, accessType); 5504baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.e(LOG_TAG, "Parsed rule: " + accessRule); 5514baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal return accessRule; 5524baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 5534baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal 5544baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal /* 5554baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal * Converts a Signature into a Certificate hash usable for comparison. 5564baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal */ 557c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu private static byte[] getCertHash(Signature signature, String algo) { 5584baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal try { 559c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu MessageDigest md = MessageDigest.getInstance(algo); 560c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu return md.digest(signature.toByteArray()); 5614baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } catch (NoSuchAlgorithmException ex) { 5624baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal Rlog.e(LOG_TAG, "NoSuchAlgorithmException: " + ex); 5634baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 5644baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal return null; 5654baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal } 566c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal 567c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal /* 568c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal * Updates the state and notifies the UiccCard that the rules have finished loading. 569c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal */ 57038aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal private void updateState(int newState, String statusMessage) { 571c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal mState.set(newState); 572c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal if (mLoadedCallback != null) { 573c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal mLoadedCallback.sendToTarget(); 574c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal } 57538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal 57638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal mStatusMessage = statusMessage; 57738aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal Rlog.e(LOG_TAG, mStatusMessage); 57838aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal } 57938aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal 58038aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal /** 58138aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal * Dumps info to Dumpsys - useful for debugging. 58238aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal */ 58338aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 58438aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal pw.println("UiccCarrierPrivilegeRules: " + this); 58538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal pw.println(" mState=" + getStateString(mState.get())); 58638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal pw.println(" mStatusMessage='" + mStatusMessage + "'"); 58738aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal if (mAccessRules != null) { 58838aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal pw.println(" mAccessRules: "); 58938aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal for (AccessRule ar : mAccessRules) { 59038aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal pw.println(" rule='" + ar + "'"); 59138aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal } 59238aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal } else { 59338aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal pw.println(" mAccessRules: null"); 59438aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal } 59538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal pw.flush(); 59638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal } 59738aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal 59838aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal /* 59938aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal * Converts state into human readable format. 60038aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal */ 60138aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal private String getStateString(int state) { 60238aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal switch (state) { 60338aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal case STATE_LOADING: 60438aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal return "STATE_LOADING"; 60538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal case STATE_LOADED: 60638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal return "STATE_LOADED"; 60738aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal case STATE_ERROR: 60838aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal return "STATE_ERROR"; 60938aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal default: 61038aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal return "UNKNOWN"; 61138aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal } 612c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal } 6134baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal} 614