UiccCarrierPrivilegeRules.java revision 91e0d7fae8ab78b99ba25aa307ec1a558b5769fc
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";
72c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu    private static final boolean DBG = false;
734baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
74e5b5f10d2d09f62c265381cab0816edfbdf566f0Junda Liu    private static final String AID = "A00000015141434C00";
754baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int CLA = 0x80;
767b122b5ef07eca751ca8b6938562737d6e3de2c8Shishir Agrawal    private static final int COMMAND = 0xCA;
777b122b5ef07eca751ca8b6938562737d6e3de2c8Shishir Agrawal    private static final int P1 = 0xFF;
787b122b5ef07eca751ca8b6938562737d6e3de2c8Shishir Agrawal    private static final int P2 = 0x40;
797541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu    private static final int P2_EXTENDED_DATA = 0x60;
804baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int P3 = 0x00;
814baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String DATA = "";
824baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
83004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu    /*
84004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     * Rules format:
85004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *   ALL_REF_AR_DO = TAG_ALL_REF_AR_DO + len + [REF_AR_DO]*n
86004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *   REF_AR_DO = TAG_REF_AR_DO + len + REF-DO + AR-DO
87004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *
88004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *   REF_DO = TAG_REF_DO + len + DEVICE_APP_ID_REF_DO + (optional) PKG_REF_DO
89004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *   AR_DO = TAG_AR_DO + len + PERM_AR_DO
90004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *
91c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu     *   DEVICE_APP_ID_REF_DO = TAG_DEVICE_APP_ID_REF_DO + len + sha256 hexstring of cert
92004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *   PKG_REF_DO = TAG_PKG_REF_DO + len + package name
93004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *   PERM_AR_DO = TAG_PERM_AR_DO + len + detailed permission (8 bytes)
94004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *
95004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     * Data objects hierarchy by TAG:
96004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     * FF40
97004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *   E2
98004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *     E1
99004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *       C1
100004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *       CA
101004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *     E3
102004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     *       DB
103004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu     */
1044baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    // Values from the data standard.
1054baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_ALL_REF_AR_DO = "FF40";
1064baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_REF_AR_DO = "E2";
1074baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_REF_DO = "E1";
1084baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_DEVICE_APP_ID_REF_DO = "C1";
1094baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final String TAG_PKG_REF_DO = "CA";
110004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu    private static final String TAG_AR_DO = "E3";
111004868eb3f91b06ef7e86b511bbb7b354036834aJunda Liu    private static final String TAG_PERM_AR_DO = "DB";
1124baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1134baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 1;
1144baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE = 2;
1154baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int EVENT_CLOSE_LOGICAL_CHANNEL_DONE = 3;
1164baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1174baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    // State of the object.
1184baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int STATE_LOADING  = 0;
1194baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int STATE_LOADED   = 1;
1204baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static final int STATE_ERROR    = 2;
1214baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
122b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu    // Max number of retries for open logical channel, interval is 10s.
12391e0d7fae8ab78b99ba25aa307ec1a558b5769fcJunda Liu    private static final int MAX_RETRY = 1;
124b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu    private static final int RETRY_INTERVAL_MS = 10000;
125b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu
1264baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    // Describes a single rule.
1274baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static class AccessRule {
1284baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public byte[] certificateHash;
1294baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public String packageName;
1304baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public long accessType;   // This bit is not currently used, but reserved for future use.
1314baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1324baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        AccessRule(byte[] certificateHash, String packageName, long accessType) {
1334baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            this.certificateHash = certificateHash;
1344baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            this.packageName = packageName;
1354baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            this.accessType = accessType;
1364baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1374baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1384baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        boolean matches(byte[] certHash, String packageName) {
1394baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal          return certHash != null && Arrays.equals(this.certificateHash, certHash) &&
1404baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                (this.packageName == null || this.packageName.equals(packageName));
1414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        @Override
1444baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public String toString() {
14538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            return "cert: " + IccUtils.bytesToHexString(certificateHash) + " pkg: " +
14638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal                packageName + " access: " + accessType;
1474baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1484baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
1494baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1504baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    // Used for parsing the data from the UICC.
1514baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private static class TLV {
1527541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu        private static final int SINGLE_BYTE_MAX_LENGTH = 0x80;
1534baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        private String tag;
1547541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu        // Length encoding is in GPC_Specification_2.2.1: 11.1.5 APDU Message and Data Length.
1557541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu        // Length field could be either 1 byte if length < 128, or multiple bytes with first byte
1567541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu        // specifying how many bytes are used for length, followed by length bytes.
1577541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu        // Bytes for the length field, in ASCII HEX string form.
1587541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu        private String lengthBytes;
1597541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu        // Decoded length as integer.
1604baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        private Integer length;
1614baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        private String value;
1624baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1634baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public TLV(String tag) {
1644baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            this.tag = tag;
1654baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
1664baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1677541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu        public String parseLength(String data) {
1687541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu            int offset = tag.length();
1697541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu            int firstByte = Integer.parseInt(data.substring(offset, offset + 2), 16);
17064e02b05d7334a9d5704ee2b9f4710a310d9937eIan Pedowitz            if (firstByte < SINGLE_BYTE_MAX_LENGTH) {
1717541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu                length = firstByte * 2;
1727541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu                lengthBytes = data.substring(offset, offset + 2);
1737541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu            } else {
1747541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu                int numBytes = firstByte - SINGLE_BYTE_MAX_LENGTH;
1757541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu                length = Integer.parseInt(data.substring(offset + 2, offset + 2 + numBytes * 2), 16) * 2;
1767541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu                lengthBytes = data.substring(offset, offset + 2 + numBytes * 2);
1777541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu            }
178c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu            log("TLV parseLength length=" + length + "lenghtBytes: " + lengthBytes);
1797541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu            return lengthBytes;
1807541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu        }
1817541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu
1824baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        public String parse(String data, boolean shouldConsumeAll) {
183c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu            log("Parse TLV: " + tag);
1844baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            if (!data.startsWith(tag)) {
1854baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                throw new IllegalArgumentException("Tags don't match.");
1864baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
1874baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            int index = tag.length();
1884baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            if (index + 2 > data.length()) {
1894baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                throw new IllegalArgumentException("No length.");
1904baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
1914baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
1927541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu            parseLength(data);
1937541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu            index += lengthBytes.length();
1947541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu
195c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu            log("index="+index+" length="+length+"data.length="+data.length());
1964baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            int remainingLength = data.length() - (index + length);
1974baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            if (remainingLength < 0) {
1984baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                throw new IllegalArgumentException("Not enough data.");
1994baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
2004baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            if (shouldConsumeAll && (remainingLength != 0)) {
2014baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                throw new IllegalArgumentException("Did not consume all.");
2024baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
2034baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            value = data.substring(index, index + length);
2044baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
205c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu            log("Got TLV: " + tag + "," + length + "," + value);
2064baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2074baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            return data.substring(index + length);
2084baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
2094baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
2104baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2114baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private UiccCard mUiccCard;  // Parent
2124baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private AtomicInteger mState;
2134baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    private List<AccessRule> mAccessRules;
2147541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu    private String mRules;
215c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal    private Message mLoadedCallback;
21638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal    private String mStatusMessage;  // Only used for debugging.
2177541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu    private int mChannelId; // Channel Id for communicating with UICC.
218b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu    private int mRetryCount;  // Number of retries for open logical channel.
219b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu    private final Runnable mRetryRunnable = new Runnable() {
220b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu        @Override
221b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu        public void run() {
222b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu            openChannel();
223b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu        }
224b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu    };
225b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu
226b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu    private void openChannel() {
227b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu        // Send open logical channel request.
228b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu        mUiccCard.iccOpenLogicalChannel(AID,
229b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu            obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, null));
230b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu    }
2314baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
232c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal    public UiccCarrierPrivilegeRules(UiccCard uiccCard, Message loadedCallback) {
233c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu        log("Creating UiccCarrierPrivilegeRules");
2344baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        mUiccCard = uiccCard;
2354baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        mState = new AtomicInteger(STATE_LOADING);
23638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        mStatusMessage = "Not loaded.";
237c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal        mLoadedCallback = loadedCallback;
2387541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu        mRules = "";
2394baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
240b757d07125d8294062586b5258e4e79d0b8417a3Junda Liu        openChannel();
2414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
2424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    /**
244c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal     * Returns true if the carrier privilege rules have finished loading.
245c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal     */
246c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal    public boolean areCarrierPriviligeRulesLoaded() {
247c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal        return mState.get() != STATE_LOADING;
248c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal    }
249c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal
250c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal    /**
251c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal     * Returns the status of the carrier privileges for the input certificate and package name.
2524baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     *
2534baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * @param signature The signature of the certificate.
2544baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * @param packageName name of the package.
2554baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * @return Access status.
2564baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     */
257c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal    public int getCarrierPrivilegeStatus(Signature signature, String packageName) {
258c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu        log("hasCarrierPrivileges: " + signature + " : " + packageName);
2594baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        int state = mState.get();
2604baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        if (state == STATE_LOADING) {
261c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu            log("Rules not loaded.");
2624baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
2634baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        } else if (state == STATE_ERROR) {
264c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu            log("Error loading rules.");
2654baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            return TelephonyManager.CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES;
2664baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
2674baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
268c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu        // SHA-1 is for backward compatible support only, strongly discouraged for new use.
269c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu        byte[] certHash = getCertHash(signature, "SHA-1");
270c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu        byte[] certHash256 = getCertHash(signature, "SHA-256");
2714baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        for (AccessRule ar : mAccessRules) {
272c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu            if (ar.matches(certHash, packageName) || ar.matches(certHash256, packageName)) {
2734baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
2744baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
2754baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
2764baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
2774baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
2784baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
2794baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
280c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal    /**
281c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal     * Returns the status of the carrier privileges for the input package name.
282c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal     *
283c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal     * @param packageManager PackageManager for getting signatures.
284c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal     * @param packageName name of the package.
285c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal     * @return Access status.
286c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal     */
287c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal    public int getCarrierPrivilegeStatus(PackageManager packageManager, String packageName) {
288c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal        try {
289cd30338d719dcd77db99766bf21438e494564174Jeff Davidson            // Include DISABLED_UNTIL_USED components. This facilitates cases where a carrier app
290cd30338d719dcd77db99766bf21438e494564174Jeff Davidson            // is disabled by default, and some other component wants to enable it when it has
291cd30338d719dcd77db99766bf21438e494564174Jeff Davidson            // gained carrier privileges (as an indication that a matching SIM has been inserted).
292c9394399180abbc32d04f6a3652ce22d5931e0b8Shishir Agrawal            PackageInfo pInfo = packageManager.getPackageInfo(packageName,
293cd30338d719dcd77db99766bf21438e494564174Jeff Davidson                PackageManager.GET_SIGNATURES | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
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:
380c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu              log("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 {
387cd30338d719dcd77db99766bf21438e494564174Jeff Davidson                  // 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:
402c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu              log("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:
438c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu              log("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() {
451c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu        log("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);
455c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu            log("isDataComplete lengthBytes: " + lengthBytes);
4567541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu            if (mRules.length() == TAG_ALL_REF_AR_DO.length() + lengthBytes.length() +
4577541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu                                   allRules.length) {
458c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu                log("isDataComplete yes");
4597541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu                return true;
4607541d468b7d9464008d6186bc7c1bcef1c925782Junda Liu            } else {
461c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu                log("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) {
473c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu        log("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) {
497c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu        log("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            } else  {
54032bbe4213fc554ebf00553cd9935d17fe7530aa1Junda Liu                // Spec requires it must be either TAG_REF_DO or TAG_AR_DO.
5414baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal                throw new RuntimeException("Invalid Rule type");
5424baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            }
5434baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
5444baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
5454baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        AccessRule accessRule = new AccessRule(IccUtils.hexStringToBytes(certificateHash),
5464baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            packageName, accessType);
5474baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        return accessRule;
5484baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
5494baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal
5504baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    /*
5514baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     * Converts a Signature into a Certificate hash usable for comparison.
5524baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal     */
553c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu    private static byte[] getCertHash(Signature signature, String algo) {
5544baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        try {
555c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu            MessageDigest md = MessageDigest.getInstance(algo);
556c05061bdcff84d8211d51a5080c57f442e4edf74Junda Liu            return md.digest(signature.toByteArray());
5574baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        } catch (NoSuchAlgorithmException ex) {
5584baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal            Rlog.e(LOG_TAG, "NoSuchAlgorithmException: " + ex);
5594baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        }
5604baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal        return null;
5614baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal    }
562c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal
563c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal    /*
564c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal     * Updates the state and notifies the UiccCard that the rules have finished loading.
565c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal     */
56638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal    private void updateState(int newState, String statusMessage) {
567c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal        mState.set(newState);
568c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal        if (mLoadedCallback != null) {
569c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal            mLoadedCallback.sendToTarget();
570c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal        }
57138aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal
57238aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        mStatusMessage = statusMessage;
573c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu    }
574c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu
575c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu    private static void log(String msg) {
576c3ac6ac3d62e0e1637ff8fddf945953dca60eebaJunda Liu        if (DBG) Rlog.d(LOG_TAG, msg);
57738aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal    }
57838aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal
57938aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal    /**
58038aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal     * Dumps info to Dumpsys - useful for debugging.
58138aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal     */
58238aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
58338aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        pw.println("UiccCarrierPrivilegeRules: " + this);
58438aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        pw.println(" mState=" + getStateString(mState.get()));
58538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        pw.println(" mStatusMessage='" + mStatusMessage + "'");
58638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        if (mAccessRules != null) {
58738aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            pw.println(" mAccessRules: ");
58838aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            for (AccessRule ar : mAccessRules) {
58938aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal                pw.println("  rule='" + ar + "'");
59038aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            }
59138aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        } else {
59238aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            pw.println(" mAccessRules: null");
59338aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        }
59438aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        pw.flush();
59538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal    }
59638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal
59738aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal    /*
59838aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal     * Converts state into human readable format.
59938aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal     */
60038aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal    private String getStateString(int state) {
60138aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal      switch (state) {
60238aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        case STATE_LOADING:
60338aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            return "STATE_LOADING";
60438aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        case STATE_LOADED:
60538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            return "STATE_LOADED";
60638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        case STATE_ERROR:
60738aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            return "STATE_ERROR";
60838aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        default:
60938aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            return "UNKNOWN";
61038aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal      }
611c9877fe39ad8f3641d16fd980404916da7f6ce70Shishir Agrawal    }
6124baf17fd699249d1b387903b6db7328ad3f7b3e2Shishir Agrawal}
613