OSDN Git Service

Make OMAPI stricter
[android-x86/frameworks-base.git] / core / java / android / se / omapi / Reader.java
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 }