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