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