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