1ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue/*
2ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * Copyright (C) 2017 The Android Open Source Project
3ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue *
4ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * Licensed under the Apache License, Version 2.0 (the "License");
5ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * you may not use this file except in compliance with the License.
6ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * You may obtain a copy of the License at
7ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue *
8ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue *      http://www.apache.org/licenses/LICENSE-2.0
9ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue *
10ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * Unless required by applicable law or agreed to in writing, software
11ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * distributed under the License is distributed on an "AS IS" BASIS,
12ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * See the License for the specific language governing permissions and
14ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * limitations under the License.
15ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue */
16ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue/*
17ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * Copyright (c) 2015-2017, The Linux Foundation.
18ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue */
19ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
20ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue/*
21ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * Contributed by: Giesecke & Devrient GmbH.
22ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue */
23ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
24ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghuepackage com.android.se;
25ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
26ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.content.Context;
27ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.content.pm.PackageManager;
28ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.hardware.secure_element.V1_0.ISecureElement;
29ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.hardware.secure_element.V1_0.ISecureElementHalCallback;
30ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.hardware.secure_element.V1_0.LogicalChannelResponse;
31ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.hardware.secure_element.V1_0.SecureElementStatus;
3257ae12642a4b355e34025f16b4bcb1c379c629e3Yoshiaki Nakaimport android.os.Build;
33cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Nakaimport android.os.Handler;
34cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Nakaimport android.os.HwBinder;
35cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Nakaimport android.os.Message;
36ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.os.RemoteException;
37ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.os.ServiceSpecificException;
38ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.se.omapi.ISecureElementListener;
39ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.se.omapi.ISecureElementReader;
40ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.se.omapi.ISecureElementSession;
41ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.se.omapi.SEService;
42ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport android.util.Log;
43ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
44ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport com.android.se.SecureElementService.SecureElementSession;
45ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport com.android.se.internal.ByteArrayConverter;
46ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport com.android.se.security.AccessControlEnforcer;
47ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport com.android.se.security.ChannelAccess;
48ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
493e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Nakaimport java.io.IOException;
50ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport java.io.PrintWriter;
51ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport java.util.ArrayList;
52ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport java.util.Collection;
53ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport java.util.HashMap;
54ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport java.util.Map;
55b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Nakaimport java.util.MissingResourceException;
56ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghueimport java.util.NoSuchElementException;
57ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
58ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue/**
59ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * Each Terminal represents a Secure Element.
60ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue * Communicates to the SE via SecureElement HAL.
61ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue */
62ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghuepublic class Terminal {
63ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
64ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private final String mTag;
65ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private final Map<Integer, Channel> mChannels = new HashMap<Integer, Channel>();
66ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private final Object mLock = new Object();
67ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private final String mName;
68ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public boolean mIsConnected = false;
69ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private Context mContext;
70ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private boolean mDefaultApplicationSelectedOnBasicChannel = true;
71ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
7257ae12642a4b355e34025f16b4bcb1c379c629e3Yoshiaki Naka    private static final boolean DEBUG = Build.IS_DEBUGGABLE;
73cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    private static final int GET_SERVICE_DELAY_MILLIS = 4 * 1000;
74cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    private static final int EVENT_GET_HAL = 1;
75ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
76ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private ISecureElement mSEHal;
77ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
78ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /** For each Terminal there will be one AccessController object. */
79ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private AccessControlEnforcer mAccessControlEnforcer;
80ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
81ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private ISecureElementHalCallback.Stub mHalCallback = new ISecureElementHalCallback.Stub() {
82ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        @Override
83ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        public void onStateChange(boolean state) {
84ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            synchronized (mLock) {
85ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                Log.i(mTag, "OnStateChange:" + state);
86ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                mIsConnected = state;
87ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                if (!state) {
88ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                    if (mAccessControlEnforcer != null) {
89ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                        mAccessControlEnforcer.reset();
90ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                    }
91ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                } else {
920f8b45235b612ac4d7a9cd7af7233039e4358b81Yukinori Sakamoto                    // If any logical channel in use is in the channel list, it should be closed
930f8b45235b612ac4d7a9cd7af7233039e4358b81Yukinori Sakamoto                    // because the access control enfocer allowed to open it by checking the access
940f8b45235b612ac4d7a9cd7af7233039e4358b81Yukinori Sakamoto                    // rules retrieved before. Now we are going to retrieve the rules again and
950f8b45235b612ac4d7a9cd7af7233039e4358b81Yukinori Sakamoto                    // the new rules can be different from the previous ones.
960f8b45235b612ac4d7a9cd7af7233039e4358b81Yukinori Sakamoto                    closeChannels();
97a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                    try {
98a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                        initializeAccessControl();
99a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                    } catch (Exception e) {
100a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                        // ignore
101a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                    }
102cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                    mDefaultApplicationSelectedOnBasicChannel = true;
103ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                }
104ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
105ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
106ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    };
107ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
108cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    class SecureElementDeathRecipient implements HwBinder.DeathRecipient {
109cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka        @Override
110cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka        public void serviceDied(long cookie) {
111cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            Log.e(mTag, mName + " died");
112cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            synchronized (mLock) {
113cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                mIsConnected = false;
114cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                if (mAccessControlEnforcer != null) {
115cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                    mAccessControlEnforcer.reset();
116cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                }
117cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            }
118cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_GET_HAL, 0),
119cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                    GET_SERVICE_DELAY_MILLIS);
120cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka        }
121cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    }
122cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka
123cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    private HwBinder.DeathRecipient mDeathRecipient = new SecureElementDeathRecipient();
124cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka
125cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    private Handler mHandler = new Handler() {
126cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka        @Override
127cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka        public void handleMessage(Message message) {
128cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            switch (message.what) {
129cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                case EVENT_GET_HAL:
130cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                    try {
131cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                        initialize();
132cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                    } catch (Exception e) {
133cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                        Log.e(mTag, mName + " could not be initialized again");
134cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                        sendMessageDelayed(obtainMessage(EVENT_GET_HAL, 0),
135cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                                GET_SERVICE_DELAY_MILLIS);
136cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                    }
137cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                    break;
138cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                default:
139cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                    break;
140cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            }
141ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
142cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    };
143cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka
144cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    public Terminal(String name, Context context) {
145ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        mContext = context;
146ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        mName = name;
147ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        mTag = "SecureElement-Terminal-" + getName();
148cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    }
149cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka
150cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    /**
151cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka     * Initializes the terminal
152cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka     *
153cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka     * @throws NoSuchElementException if there is no HAL implementation for the specified SE name
154cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka     * @throws RemoteException if there is a failure communicating with the remote
155cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka     */
156cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    public void initialize() throws NoSuchElementException, RemoteException {
157cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka        synchronized (mLock) {
158cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            mSEHal = ISecureElement.getService(mName);
159cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            if (mSEHal == null) {
160cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                throw new NoSuchElementException("No HAL is provided for " + mName);
161cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            }
162cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            mSEHal.init(mHalCallback);
163cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            mSEHal.linkToDeath(mDeathRecipient, 0);
164ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
165cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka        Log.i(mTag, mName + " was initialized");
166ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
167ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
168ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private ArrayList<Byte> byteArrayToArrayList(byte[] array) {
169ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        ArrayList<Byte> list = new ArrayList<Byte>();
170ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (array == null) {
171ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return list;
172ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
173ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
174ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        for (Byte b : array) {
175ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            list.add(b);
176ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
177ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        return list;
178ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
179ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
180ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    private byte[] arrayListToByteArray(ArrayList<Byte> list) {
181ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        Byte[] byteArray = list.toArray(new Byte[list.size()]);
182ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        int i = 0;
183ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        byte[] result = new byte[list.size()];
184ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        for (Byte b : byteArray) {
185ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            result[i++] = b.byteValue();
186ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
187ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        return result;
188ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
189ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
190ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
191ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Closes the given channel
192ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
193ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public void closeChannel(Channel channel) {
194ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (channel == null) {
195ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return;
196ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
197fffcc4e3ff78f746101858c1e055ae681ea343a7Ruchi Kandoi        if (mIsConnected) {
198ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            try {
199ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                byte status = mSEHal.closeChannel((byte) channel.getChannelNumber());
200fffcc4e3ff78f746101858c1e055ae681ea343a7Ruchi Kandoi                /* For Basic Channels, errors are expected.
201fffcc4e3ff78f746101858c1e055ae681ea343a7Ruchi Kandoi                 * Underlying implementations use this call as an indication when there
202fffcc4e3ff78f746101858c1e055ae681ea343a7Ruchi Kandoi                 * aren't any users actively using the channel, and the chip can go
203fffcc4e3ff78f746101858c1e055ae681ea343a7Ruchi Kandoi                 * into low power state.
204fffcc4e3ff78f746101858c1e055ae681ea343a7Ruchi Kandoi                 */
205fffcc4e3ff78f746101858c1e055ae681ea343a7Ruchi Kandoi                if (!channel.isBasicChannel() && status != SecureElementStatus.SUCCESS) {
206ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                    Log.e(mTag, "Error closing channel " + channel.getChannelNumber());
207ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                }
208ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            } catch (RemoteException e) {
209ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                Log.e(mTag, "Exception in closeChannel() " + e);
210ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
211ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
212ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        synchronized (mLock) {
213ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            mChannels.remove(channel.getChannelNumber(), channel);
214ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (mChannels.get(channel.getChannelNumber()) != null) {
215ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                Log.e(mTag, "Removing channel failed");
216ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
217ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
218ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
219ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
220ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
2210f8b45235b612ac4d7a9cd7af7233039e4358b81Yukinori Sakamoto     * Cleans up all the channels in use.
222ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
223ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public synchronized void closeChannels() {
224ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        Collection<Channel> col = mChannels.values();
225ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        Channel[] channelList = col.toArray(new Channel[col.size()]);
226ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        for (Channel channel : channelList) {
2270f8b45235b612ac4d7a9cd7af7233039e4358b81Yukinori Sakamoto            channel.close();
228ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
229ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
230ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
231cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    /**
232cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka     * Closes the terminal.
233cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka     */
234cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    public void close() {
235cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka        synchronized (mLock) {
236cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            if (mSEHal != null) {
237cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                try {
238cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                    mSEHal.unlinkToDeath(mDeathRecipient);
239cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                } catch (RemoteException e) {
240cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                    // ignore
241cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka                }
242cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka            }
243cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka        }
244cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka    }
245cf7d2f1d5d06675593e770e267d318357b598fdcYoshiaki Naka
246ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public String getName() {
247ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        return mName;
248ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
249ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
250ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
251ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Returns the ATR of the Secure Element, or null if not available.
252ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
253ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public byte[] getAtr() {
254ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (!mIsConnected) {
255ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return null;
256ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
257ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
258ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        try {
259ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            ArrayList<Byte> responseList = mSEHal.getAtr();
260ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (responseList.isEmpty()) {
261ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return null;
262ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
263ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return arrayListToByteArray(responseList);
264ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        } catch (RemoteException e) {
265ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            Log.e(mTag, "Exception in getAtr()" + e);
266ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return null;
267ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
268ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
269ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
270ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
271ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Selects the default application on the basic channel.
272ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     *
273ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * If there is an exception selecting the default application, select
274ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * is performed with the default access control aid.
275ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
276ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public void selectDefaultApplication() {
277ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        try {
278ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            select(null);
279ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        } catch (NoSuchElementException e) {
280ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (getAccessControlEnforcer() != null) {
281ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                try {
282ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                    select(mAccessControlEnforcer.getDefaultAccessControlAid());
283ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                } catch (Exception ignore) {
284ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                }
285ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
2863878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka        } catch (Exception ignore) {
287ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
288ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
289ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
2903878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka    private void select(byte[] aid) throws IOException {
291ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        int commandSize = (aid == null ? 0 : aid.length) + 5;
292ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        byte[] selectCommand = new byte[commandSize];
293ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        selectCommand[0] = 0x00;
294ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        selectCommand[1] = (byte) 0xA4;
295ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        selectCommand[2] = 0x04;
296ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        selectCommand[3] = 0x00;
297ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (aid != null && aid.length != 0) {
298ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            selectCommand[4] = (byte) aid.length;
299ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            System.arraycopy(aid, 0, selectCommand, 5, aid.length);
300ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        } else {
301ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            selectCommand[4] = 0x00;
302ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
303ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        byte[] selectResponse = transmit(selectCommand);
304ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (selectResponse.length < 2) {
305ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            selectResponse = null;
306ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            throw new NoSuchElementException("Response length is too small");
307ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
308e6556339e7843be665238dd9b53a22a37d4eddb7Ruchi Kandoi        int sw1 = selectResponse[selectResponse.length - 2] & 0xFF;
309e6556339e7843be665238dd9b53a22a37d4eddb7Ruchi Kandoi        int sw2 = selectResponse[selectResponse.length - 1] & 0xFF;
310ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (sw1 != 0x90 || sw2 != 0x00) {
311ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            selectResponse = null;
312ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            throw new NoSuchElementException("Status word is incorrect");
313ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
314ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
315ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
316ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
317ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Opens a Basic Channel with the given AID and P2 paramters
318ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
319ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public Channel openBasicChannel(SecureElementSession session, byte[] aid, byte p2,
3205091d61f6760b87dc00d48040fad9da6509a522bYoshiaki Naka            ISecureElementListener listener, String packageName, int pid) throws IOException,
3215091d61f6760b87dc00d48040fad9da6509a522bYoshiaki Naka            NoSuchElementException {
322ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (aid != null && aid.length == 0) {
323ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            aid = null;
324ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        } else if (aid != null && (aid.length < 5 || aid.length > 16)) {
325ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            throw new IllegalArgumentException("AID out of range");
3263e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka        } else if (!mIsConnected) {
3273e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka            throw new IOException("Secure Element is not connected");
328ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
329ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
330ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        Log.w(mTag, "Enable access control on basic channel for " + packageName);
331b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Naka        ChannelAccess channelAccess;
332b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Naka        try {
333a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            channelAccess = setUpChannelAccess(aid, packageName, pid);
334b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Naka        } catch (MissingResourceException e) {
335b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Naka            return null;
336b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Naka        }
337ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
338ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        synchronized (mLock) {
339ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (mChannels.get(0) != null) {
340ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                Log.e(mTag, "basic channel in use");
341ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return null;
342ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
343ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (aid == null && !mDefaultApplicationSelectedOnBasicChannel) {
344ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                Log.e(mTag, "default application is not selected");
345ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return null;
346ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
347ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
348ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            ArrayList<byte[]> responseList = new ArrayList<byte[]>();
349ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            byte[] status = new byte[1];
3503e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka
3513e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka            try {
3523e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                mSEHal.openBasicChannel(byteArrayToArrayList(aid), p2,
3533e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                        new ISecureElement.openBasicChannelCallback() {
3543e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                            @Override
3553e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                            public void onValues(ArrayList<Byte> responseObject, byte halStatus) {
3563e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                                status[0] = halStatus;
3573e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                                responseList.add(arrayListToByteArray(responseObject));
3583e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                                return;
3593e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                            }
3603e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                        });
3613e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka            } catch (RemoteException e) {
3623e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                throw new IOException(e.getMessage());
3633e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka            }
3643e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka
365ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            byte[] selectResponse = responseList.get(0);
366ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (status[0] == SecureElementStatus.CHANNEL_NOT_AVAILABLE) {
367ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return null;
368ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            } else if (status[0] == SecureElementStatus.UNSUPPORTED_OPERATION) {
369ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                throw new UnsupportedOperationException("OpenBasicChannel() failed");
370ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            } else if (status[0] == SecureElementStatus.IOERROR) {
3713e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                throw new IOException("OpenBasicChannel() failed");
372e6556339e7843be665238dd9b53a22a37d4eddb7Ruchi Kandoi            } else if (status[0] == SecureElementStatus.NO_SUCH_ELEMENT_ERROR) {
3735091d61f6760b87dc00d48040fad9da6509a522bYoshiaki Naka                throw new NoSuchElementException("OpenBasicChannel() failed");
374ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
375e6556339e7843be665238dd9b53a22a37d4eddb7Ruchi Kandoi
376ee4e841e19af13ab78b7b7f385c3245019ff3806Ruchi Kandoi            Channel basicChannel = new Channel(session, this, 0, selectResponse, aid,
377ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                    listener);
378ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            basicChannel.setChannelAccess(channelAccess);
379ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
380ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (aid != null) {
381ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                mDefaultApplicationSelectedOnBasicChannel = false;
382ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
383ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            mChannels.put(0, basicChannel);
384ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return basicChannel;
385ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
386ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
387ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
388ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
389ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Opens a logical Channel without Channel Access initialization.
390ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
3915091d61f6760b87dc00d48040fad9da6509a522bYoshiaki Naka    public Channel openLogicalChannelWithoutChannelAccess(byte[] aid) throws IOException,
3925091d61f6760b87dc00d48040fad9da6509a522bYoshiaki Naka            NoSuchElementException {
393ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        return openLogicalChannel(null, aid, (byte) 0x00, null, null, 0);
394ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
395ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
396ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
397ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Opens a logical Channel with AID.
398ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
3993e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka    public Channel openLogicalChannel(SecureElementSession session, byte[] aid, byte p2,
4005091d61f6760b87dc00d48040fad9da6509a522bYoshiaki Naka            ISecureElementListener listener, String packageName, int pid) throws IOException,
4015091d61f6760b87dc00d48040fad9da6509a522bYoshiaki Naka            NoSuchElementException {
402ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (aid != null && aid.length == 0) {
403ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            aid = null;
404ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        } else if (aid != null && (aid.length < 5 || aid.length > 16)) {
405ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            throw new IllegalArgumentException("AID out of range");
406ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        } else if (!mIsConnected) {
4073e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka            throw new IOException("Secure Element is not connected");
408ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
409ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
410ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        ChannelAccess channelAccess = null;
411ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (packageName != null) {
412ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            Log.w(mTag, "Enable access control on logical channel for " + packageName);
413b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Naka            try {
414a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                channelAccess = setUpChannelAccess(aid, packageName, pid);
415b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Naka            } catch (MissingResourceException e) {
416b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Naka                return null;
417b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Naka            }
418ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
419ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
420ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        synchronized (mLock) {
421ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            LogicalChannelResponse[] responseArray = new LogicalChannelResponse[1];
422ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            byte[] status = new byte[1];
4233e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka
4243e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka            try {
4253e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                mSEHal.openLogicalChannel(byteArrayToArrayList(aid), p2,
4263e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                        new ISecureElement.openLogicalChannelCallback() {
4273e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                            @Override
4283e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                            public void onValues(LogicalChannelResponse response, byte halStatus) {
4293e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                                status[0] = halStatus;
4303e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                                responseArray[0] = response;
4313e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                                return;
4323e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                            }
4333e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                        });
4343e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka            } catch (RemoteException e) {
4353e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                throw new IOException(e.getMessage());
4363e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka            }
4373e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka
438ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (status[0] == SecureElementStatus.CHANNEL_NOT_AVAILABLE) {
439ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return null;
440ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            } else if (status[0] == SecureElementStatus.UNSUPPORTED_OPERATION) {
441ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                throw new UnsupportedOperationException("OpenLogicalChannel() failed");
442ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            } else if (status[0] == SecureElementStatus.IOERROR) {
4433e785e28c90aefc1a5c09f089684fdd48633fa32Yoshiaki Naka                throw new IOException("OpenLogicalChannel() failed");
444ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            } else if (status[0] == SecureElementStatus.NO_SUCH_ELEMENT_ERROR) {
4455091d61f6760b87dc00d48040fad9da6509a522bYoshiaki Naka                throw new NoSuchElementException("OpenLogicalChannel() failed");
446ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
447ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (responseArray[0].channelNumber <= 0 || status[0] != SecureElementStatus.SUCCESS) {
448ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return null;
449ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
450ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            int channelNumber = responseArray[0].channelNumber;
451ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            byte[] selectResponse = arrayListToByteArray(responseArray[0].selectResponse);
452ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            Channel logicalChannel = new Channel(session, this, channelNumber,
453ee4e841e19af13ab78b7b7f385c3245019ff3806Ruchi Kandoi                    selectResponse, aid, listener);
454ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            logicalChannel.setChannelAccess(channelAccess);
455ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
456ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            mChannels.put(channelNumber, logicalChannel);
457ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return logicalChannel;
458ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
459ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
460ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
461ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
462ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Returns true if the given AID can be selected on the Terminal
463ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
464ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public boolean isAidSelectable(byte[] aid) {
465ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (aid == null) {
466ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            throw new NullPointerException("aid must not be null");
467ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        } else if (!mIsConnected) {
468ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            Log.e(mTag, "Secure Element is not connected");
469ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return false;
470ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
471ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
472ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        synchronized (mLock) {
473ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            LogicalChannelResponse[] responseArray = new LogicalChannelResponse[1];
474ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            byte[] status = new byte[1];
475ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            try {
476ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                mSEHal.openLogicalChannel(byteArrayToArrayList(aid), (byte) 0x00,
477ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                        new ISecureElement.openLogicalChannelCallback() {
478ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                            @Override
479ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                            public void onValues(LogicalChannelResponse response, byte halStatus) {
480ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                                status[0] = halStatus;
481ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                                responseArray[0] = response;
482ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                                return;
483ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                            }
484ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                        });
485ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                if (status[0] == SecureElementStatus.SUCCESS) {
486ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                    mSEHal.closeChannel(responseArray[0].channelNumber);
487ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                    return true;
488ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                }
489ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return false;
490ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            } catch (RemoteException e) {
491ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                Log.e(mTag, "Error in isAidSelectable() returning false" + e);
492ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return false;
493ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
494ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
495ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
496ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
497ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
498ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Transmits the specified command and returns the response.
499ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     *
500ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * @param cmd the command APDU to be transmitted.
501ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * @return the response received.
502ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
5033878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka    public byte[] transmit(byte[] cmd) throws IOException {
504ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (!mIsConnected) {
505ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            Log.e(mTag, "Secure Element is not connected");
5063878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka            throw new IOException("Secure Element is not connected");
507ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
508ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
509ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        byte[] rsp = transmitInternal(cmd);
510ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        int sw1 = rsp[rsp.length - 2] & 0xFF;
511ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        int sw2 = rsp[rsp.length - 1] & 0xFF;
512ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
513ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (sw1 == 0x6C) {
514ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            cmd[cmd.length - 1] = rsp[rsp.length - 1];
515ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            rsp = transmitInternal(cmd);
516ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        } else if (sw1 == 0x61) {
517ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            do {
518ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                byte[] getResponseCmd = new byte[]{
519ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                        cmd[0], (byte) 0xC0, 0x00, 0x00, (byte) sw2
520ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                };
521ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                byte[] tmp = transmitInternal(getResponseCmd);
522ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                byte[] aux = rsp;
523ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                rsp = new byte[aux.length + tmp.length - 2];
524ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                System.arraycopy(aux, 0, rsp, 0, aux.length - 2);
525ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                System.arraycopy(tmp, 0, rsp, aux.length - 2, tmp.length);
526ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                sw1 = rsp[rsp.length - 2] & 0xFF;
527ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                sw2 = rsp[rsp.length - 1] & 0xFF;
528ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            } while (sw1 == 0x61);
529ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
530ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        return rsp;
531ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
532ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
5333878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka    private byte[] transmitInternal(byte[] cmd) throws IOException {
5343878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka        ArrayList<Byte> response;
5353878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka        try {
5363878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka            response = mSEHal.transmit(byteArrayToArrayList(cmd));
5373878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka        } catch (RemoteException e) {
5383878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka            throw new IOException(e.getMessage());
5393878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka        }
540ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (response.isEmpty()) {
5413878ce67ae4810258882c749f4dcbf508e6ad9edYoshiaki Naka            throw new IOException("Error in transmit()");
542ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
543ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        byte[] rsp = arrayListToByteArray(response);
54457ae12642a4b355e34025f16b4bcb1c379c629e3Yoshiaki Naka        if (DEBUG) {
545ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            Log.i(mTag, "Sent : " + ByteArrayConverter.byteArrayToHexString(cmd));
546ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            Log.i(mTag, "Received : " + ByteArrayConverter.byteArrayToHexString(rsp));
547ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
548ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        return rsp;
549ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
550ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
551ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
552ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Checks if the application is authorized to receive the transaction event.
553ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
554a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka    public boolean[] isNfcEventAllowed(PackageManager packageManager, byte[] aid,
555a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            String[] packageNames) {
556a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka        boolean checkRefreshTag = true;
557ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (mAccessControlEnforcer == null) {
558a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            try {
559a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                initializeAccessControl();
560a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                // Just finished to initialize the access control enforcer.
561a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                // It is too much to check the refresh tag in this case.
562a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                checkRefreshTag = false;
563a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            } catch (Exception e) {
564a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                Log.i(mTag, "isNfcEventAllowed Exception: " + e.getMessage());
565a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                return null;
566a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            }
567ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
568ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        mAccessControlEnforcer.setPackageManager(packageManager);
569ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
570ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        synchronized (mLock) {
571ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            try {
572ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return mAccessControlEnforcer.isNfcEventAllowed(aid, packageNames,
573ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                        checkRefreshTag);
574ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            } catch (Exception e) {
575ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                Log.i(mTag, "isNfcEventAllowed Exception: " + e.getMessage());
576ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return null;
577ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
578ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
579ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
580ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
581ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
582ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Returns true if the Secure Element is present
583ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
584ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public boolean isSecureElementPresent() {
585ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        try {
586ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return mSEHal.isCardPresent();
587ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        } catch (RemoteException e) {
588ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            Log.e(mTag, "Error in isSecureElementPresent() " + e);
589ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return false;
590ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
591ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
592ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
593ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
594ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Initialize the Access Control and set up the channel access.
595ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
596a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka    private ChannelAccess setUpChannelAccess(byte[] aid, String packageName, int pid)
597a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            throws IOException, MissingResourceException {
598a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka        boolean checkRefreshTag = true;
599ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (mAccessControlEnforcer == null) {
600ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            initializeAccessControl();
601a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            // Just finished to initialize the access control enforcer.
602a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            // It is too much to check the refresh tag in this case.
603a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            checkRefreshTag = false;
604ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
605ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        mAccessControlEnforcer.setPackageManager(mContext.getPackageManager());
606ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
607ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        synchronized (mLock) {
608ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            try {
609ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                ChannelAccess channelAccess =
610ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                        mAccessControlEnforcer.setUpChannelAccess(aid, packageName,
611ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                                checkRefreshTag);
612ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                channelAccess.setCallingPid(pid);
613ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return channelAccess;
614a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            } catch (IOException | MissingResourceException e) {
615b36dd054b47593b8a6b7d199aaf3336fe6ec70e8Yoshiaki Naka                throw e;
616ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            } catch (Exception e) {
617ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                throw new SecurityException("Exception in setUpChannelAccess()" + e);
618ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
619ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
620ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
621ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
622ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /**
623ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     * Initializes the Access Control for this Terminal
624ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue     */
625a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka    private synchronized void initializeAccessControl() throws IOException,
626a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            MissingResourceException {
627ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        synchronized (mLock) {
628ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (mAccessControlEnforcer == null) {
629ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                mAccessControlEnforcer = new AccessControlEnforcer(this);
630ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
631a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            try {
632a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                mAccessControlEnforcer.initialize();
633a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            } catch (IOException | MissingResourceException e) {
634a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                // Retrieving access rules failed because of an IO error happened between
635a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                // the terminal and the secure element or the lack of a logical channel available.
636a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                // It might be a temporary failure, so the terminal shall attempt to cache
637a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                // the access rules again later.
638a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                mAccessControlEnforcer = null;
639a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka                throw e;
640a726b469d3c61c4dab20aefa75408d363431bf6aYoshiaki Naka            }
641ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
642ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
643ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
644ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public AccessControlEnforcer getAccessControlEnforcer() {
645ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        return mAccessControlEnforcer;
646ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
647ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
648ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    /** Dump data for debug purpose . */
649ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    public void dump(PrintWriter writer) {
650ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        writer.println("SECURE ELEMENT SERVICE TERMINAL: " + mName);
651ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        writer.println();
652ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
653ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        writer.println("mIsConnected:" + mIsConnected);
654ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        writer.println();
655ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
656ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        /* Dump the list of currunlty openned channels */
657ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        writer.println("List of open channels:");
658ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
659ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        for (Channel channel : mChannels.values()) {
660ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            writer.println("channel " + channel.getChannelNumber() + ": ");
661ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            writer.println("package: " + channel.getChannelAccess().getPackageName());
662ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            writer.println("pid: " + channel.getChannelAccess().getCallingPid());
663ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            writer.println("aid selected: " + channel.hasSelectedAid());
664ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            writer.println("basic channel: " + channel.isBasicChannel());
665ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            writer.println();
666ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
667ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        writer.println();
668ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
669ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        /* Dump ACE data */
670ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        if (mAccessControlEnforcer != null) {
671ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            mAccessControlEnforcer.dump(writer);
672ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
673ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
674ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
675ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    // Implementation of the SecureElement Reader interface according to OMAPI.
676ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    final class SecureElementReader extends ISecureElementReader.Stub {
677ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
678ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        private final SecureElementService mService;
679ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        private final ArrayList<SecureElementSession> mSessions =
680ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                new ArrayList<SecureElementSession>();
681ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
682ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        SecureElementReader(SecureElementService service) {
683ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            mService = service;
684ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
685ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
686ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        public byte[] getAtr() {
687ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return Terminal.this.getAtr();
688ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
689ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
690ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        @Override
691ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        public boolean isSecureElementPresent() throws RemoteException {
692ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return Terminal.this.isSecureElementPresent();
693ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
694ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
695ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        @Override
696ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        public void closeSessions() {
697ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            synchronized (mLock) {
698ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                while (mSessions.size() > 0) {
699ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                    try {
700ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                        mSessions.get(0).close();
701ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                    } catch (Exception ignore) {
702ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                    }
703ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                }
704ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                mSessions.clear();
705ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
706ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
707ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
708ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        public void removeSession(SecureElementSession session) {
709ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (session == null) {
710ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                throw new NullPointerException("session is null");
711ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
712ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            mSessions.remove(session);
713e6556339e7843be665238dd9b53a22a37d4eddb7Ruchi Kandoi            synchronized (mLock) {
714e6556339e7843be665238dd9b53a22a37d4eddb7Ruchi Kandoi                if (mSessions.size() == 0) {
715e6556339e7843be665238dd9b53a22a37d4eddb7Ruchi Kandoi                    mDefaultApplicationSelectedOnBasicChannel = true;
716e6556339e7843be665238dd9b53a22a37d4eddb7Ruchi Kandoi                }
717e6556339e7843be665238dd9b53a22a37d4eddb7Ruchi Kandoi            }
718ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
719ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
720ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        @Override
721ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        public ISecureElementSession openSession() throws RemoteException {
722ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            if (!isSecureElementPresent()) {
723ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                throw new ServiceSpecificException(SEService.IO_ERROR,
724ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                        "Secure Element is not present.");
725ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
726ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
727ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            synchronized (mLock) {
728ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                SecureElementSession session = mService.new SecureElementSession(this);
729ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                mSessions.add(session);
730ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue                return session;
731ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            }
732ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
733ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue
734ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        Terminal getTerminal() {
735ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue            return Terminal.this;
736ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue        }
737ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue    }
738ab336de91e0468a1352d1a9f5d92f219140e0bd1Jeremy O'Donoghue}
739