blob: 80262f7533c8b8ea9e3048a564f0b06759b6b809 [file] [log] [blame]
Ruchi Kandoia1f94012017-12-08 15:07:03 -08001/*
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
23package android.se.omapi;
24
25import android.annotation.NonNull;
26import android.os.RemoteException;
Ruchi Kandoi816a0532018-02-01 16:15:25 -080027import android.os.ServiceSpecificException;
Ruchi Kandoia1f94012017-12-08 15:07:03 -080028import android.util.Log;
29
30import 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 */
Ruchi Kandoif0082402018-03-27 10:03:34 -070040public final class Reader {
Ruchi Kandoia1f94012017-12-08 15:07:03 -080041
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
Ruchi Kandoid785fc42018-03-22 11:06:36 -070049 Reader(@NonNull SEService service, @NonNull String name, @NonNull ISecureElementReader reader) {
Ruchi Kandoia1f94012017-12-08 15:07:03 -080050 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();
Ruchi Kandoi816a0532018-02-01 16:15:25 -080099 } catch (ServiceSpecificException e) {
Ruchi Kandoia1f94012017-12-08 15:07:03 -0800100 throw new IOException(e.getMessage());
Ruchi Kandoi816a0532018-02-01 16:15:25 -0800101 } catch (RemoteException e) {
102 throw new IllegalStateException(e.getMessage());
Ruchi Kandoia1f94012017-12-08 15:07:03 -0800103 }
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}