Home | History | Annotate | Download | only in omapi
      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  * Contributed by: Giesecke & Devrient GmbH.
     21  */
     22 
     23 package android.se.omapi;
     24 
     25 import android.annotation.NonNull;
     26 import android.os.RemoteException;
     27 import android.os.ServiceSpecificException;
     28 import android.util.Log;
     29 
     30 import java.io.IOException;
     31 
     32 /**
     33  * Instances of this class represent Secure Element Readers supported to this
     34  * device. These Readers can be physical devices or virtual devices. They can be
     35  * removable or not. They can contain Secure Element that can or cannot be
     36  * removed.
     37  *
     38  * @see <a href="http://globalplatform.org">GlobalPlatform Open Mobile API</a>
     39  */
     40 public final class Reader {
     41 
     42     private static final String TAG = "OMAPI.Reader";
     43     private final String mName;
     44     private final SEService mService;
     45     private ISecureElementReader mReader;
     46     private final Object mLock = new Object();
     47 
     48 
     49     Reader(@NonNull SEService service, @NonNull String name, @NonNull ISecureElementReader reader) {
     50         if (reader == null || service == null || name == null) {
     51             throw new IllegalArgumentException("Parameters cannot be null");
     52         }
     53         mName = name;
     54         mService = service;
     55         mReader = reader;
     56     }
     57 
     58     /**
     59      * Return the name of this reader.
     60      * <ul>
     61      * <li>If this reader is a SIM reader, then its name must be "SIM[Slot]".</li>
     62      * <li>If the reader is a SD or micro SD reader, then its name must be "SD[Slot]"</li>
     63      * <li>If the reader is a embedded SE reader, then its name must be "eSE[Slot]"</li>
     64      * </ul>
     65      * Slot is a decimal number without leading zeros. The Numbering must start with 1
     66      * (e.g. SIM1, SIM2, ... or SD1, SD2, ... or eSE1, eSE2, ...).
     67      * The slot number 1 for a reader is optional
     68      * (SIM and SIM1 are both valid for the first SIM-reader,
     69      * but if there are two readers then the second reader must be named SIM2).
     70      * This applies also for other SD or SE readers.
     71      *
     72      * @return the reader name, as a String.
     73      */
     74     public @NonNull String getName() {
     75         return mName;
     76     }
     77 
     78     /**
     79      * Connects to a Secure Element in this reader. <br>
     80      * This method prepares (initialises) the Secure Element for communication
     81      * before the Session object is returned (e.g. powers the Secure Element by
     82      * ICC ON if its not already on). There might be multiple sessions opened at
     83      * the same time on the same reader. The system ensures the interleaving of
     84      * APDUs between the respective sessions.
     85      *
     86      * @throws IOException if something went wrong with the communicating to the
     87      *             Secure Element or the reader.
     88      * @return a Session object to be used to create Channels.
     89      */
     90     public @NonNull Session openSession() throws IOException {
     91         if (!mService.isConnected()) {
     92             throw new IllegalStateException("service is not connected");
     93         }
     94 
     95         synchronized (mLock) {
     96             ISecureElementSession session;
     97             try {
     98                 session = mReader.openSession();
     99             } catch (ServiceSpecificException e) {
    100                 throw new IOException(e.getMessage());
    101             } catch (RemoteException e) {
    102                 throw new IllegalStateException(e.getMessage());
    103             }
    104             if (session == null) {
    105                 throw new IOException("service session is null.");
    106             }
    107             return new Session(mService, session, this);
    108         }
    109     }
    110 
    111     /**
    112      * Check if a Secure Element is present in this reader.
    113      *
    114      * @throws IllegalStateException if the service is not connected
    115      * @return <code>true</code> if the SE is present, <code>false</code> otherwise.
    116      */
    117     public boolean isSecureElementPresent() {
    118         if (!mService.isConnected()) {
    119             throw new IllegalStateException("service is not connected");
    120         }
    121 
    122         try {
    123             return mReader.isSecureElementPresent();
    124         } catch (RemoteException e) {
    125             throw new IllegalStateException("Error in isSecureElementPresent()");
    126         }
    127     }
    128 
    129     /**
    130      * Return the Secure Element service this reader is bound to.
    131      *
    132      * @return the SEService object.
    133      */
    134     public @NonNull SEService getSEService() {
    135         return mService;
    136     }
    137 
    138     /**
    139      * Close all the sessions opened on this reader.
    140      * All the channels opened by all these sessions will be closed.
    141      */
    142     public void closeSessions() {
    143         if (!mService.isConnected()) {
    144             Log.e(TAG, "service is not connected");
    145             return;
    146         }
    147         synchronized (mLock) {
    148             try {
    149                 mReader.closeSessions();
    150             } catch (RemoteException ignore) { }
    151         }
    152     }
    153 }
    154