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) 2014-2017, The Linux Foundation. 18 */ 19 /* 20 * Contributed by: Giesecke & Devrient GmbH. 21 */ 22 23 package com.android.se; 24 25 import android.app.Service; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.content.pm.PackageManager; 31 import android.os.Binder; 32 import android.os.Build; 33 import android.os.IBinder; 34 import android.os.RemoteException; 35 import android.os.ServiceManager; 36 import android.os.ServiceSpecificException; 37 import android.se.omapi.ISecureElementChannel; 38 import android.se.omapi.ISecureElementListener; 39 import android.se.omapi.ISecureElementReader; 40 import android.se.omapi.ISecureElementService; 41 import android.se.omapi.ISecureElementSession; 42 import android.se.omapi.SEService; 43 import android.telephony.TelephonyManager; 44 import android.util.Log; 45 46 import com.android.se.Terminal.SecureElementReader; 47 import com.android.se.internal.ByteArrayConverter; 48 49 import java.io.FileDescriptor; 50 import java.io.IOException; 51 import java.io.PrintWriter; 52 import java.security.AccessControlException; 53 import java.util.ArrayList; 54 import java.util.LinkedHashMap; 55 import java.util.List; 56 import java.util.NoSuchElementException; 57 58 /** 59 * Underlying implementation for OMAPI SEService 60 */ 61 public final class SecureElementService extends Service { 62 63 public static final String UICC_TERMINAL = "SIM"; 64 public static final String ESE_TERMINAL = "eSE"; 65 private final String mTag = "SecureElementService"; 66 private static final boolean DEBUG = Build.IS_DEBUGGABLE; 67 // LinkedHashMap will maintain the order of insertion 68 private LinkedHashMap<String, Terminal> mTerminals = new LinkedHashMap<String, Terminal>(); 69 private int mActiveSimCount = 0; 70 private final ISecureElementService.Stub mSecureElementServiceBinder = 71 new ISecureElementService.Stub() { 72 73 @Override 74 public String[] getReaders() throws RemoteException { 75 return mTerminals.keySet().toArray(new String[mTerminals.size()]); 76 } 77 78 @Override 79 public ISecureElementReader getReader(String reader) 80 throws RemoteException { 81 Log.d(mTag, "getReader() " + reader); 82 Terminal terminal = getTerminal(reader); 83 return terminal.new SecureElementReader(SecureElementService.this); 84 } 85 86 @Override 87 public synchronized boolean[] isNFCEventAllowed(String reader, byte[] aid, 88 String[] packageNames) 89 throws RemoteException { 90 if (aid == null || aid.length == 0) { 91 aid = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00}; 92 } 93 if (aid.length < 5 || aid.length > 16) { 94 throw new IllegalArgumentException("AID out of range"); 95 } 96 if (packageNames == null || packageNames.length == 0) { 97 throw new IllegalArgumentException("package names not specified"); 98 } 99 Terminal terminal = getTerminal(reader); 100 return terminal.isNfcEventAllowed(getPackageManager(), aid, packageNames); 101 } 102 103 @Override 104 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 105 for (Terminal terminal : mTerminals.values()) { 106 terminal.dump(writer); 107 } 108 } 109 }; 110 SecureElementService()111 public SecureElementService() { 112 super(); 113 } 114 initialize()115 private void initialize() { 116 // listen for events 117 IntentFilter intentFilter = new IntentFilter(); 118 intentFilter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED); 119 this.registerReceiver(mMultiSimConfigChangedReceiver, intentFilter); 120 } 121 122 /** Returns the terminal from the Reader name. */ getTerminal(String reader)123 private Terminal getTerminal(String reader) { 124 if (reader == null) { 125 throw new NullPointerException("reader must not be null"); 126 } 127 if (reader.equals("SIM")) { 128 reader = "SIM1"; 129 } 130 Terminal terminal = mTerminals.get(reader); 131 if (terminal == null) { 132 throw new IllegalArgumentException("Reader: " + reader + " doesn't exist"); 133 } 134 return terminal; 135 } 136 137 @Override onBind(Intent intent)138 public IBinder onBind(Intent intent) { 139 Log.i(mTag, Thread.currentThread().getName() + " onBind"); 140 if (ISecureElementService.class.getName().equals(intent.getAction())) { 141 return mSecureElementServiceBinder; 142 } 143 return null; 144 } 145 146 @Override onCreate()147 public void onCreate() { 148 Log.i(mTag, Thread.currentThread().getName() + " onCreate"); 149 initialize(); 150 createTerminals(); 151 ServiceManager.addService(Context.SECURE_ELEMENT_SERVICE, mSecureElementServiceBinder); 152 } 153 154 /** 155 * In case the onDestroy is called, we free the memory and 156 * close all the channels. 157 */ onDestroy()158 public void onDestroy() { 159 Log.i(mTag, "onDestroy"); 160 for (Terminal terminal : mTerminals.values()) { 161 terminal.closeChannels(); 162 terminal.close(); 163 } 164 if (mMultiSimConfigChangedReceiver != null) { 165 this.unregisterReceiver(mMultiSimConfigChangedReceiver); 166 } 167 } 168 addTerminals(String terminalName)169 private void addTerminals(String terminalName) { 170 int index = 1; 171 String name = null; 172 if (terminalName.startsWith(SecureElementService.UICC_TERMINAL)) { 173 index = mActiveSimCount + 1; 174 } 175 try { 176 do { 177 name = terminalName + Integer.toString(index); 178 Terminal terminal = new Terminal(name, this); 179 180 Log.i(mTag, "Check if terminal " + name + " is available."); 181 // Only retry on fail for the first terminal of each type. 182 terminal.initialize(index == 1); 183 mTerminals.put(name, terminal); 184 if (terminalName.equals(UICC_TERMINAL)) { 185 mActiveSimCount = index; 186 } 187 } while (++index > 0); 188 } catch (NoSuchElementException e) { 189 Log.i(mTag, "No HAL implementation for " + name); 190 } catch (RemoteException | RuntimeException e) { 191 Log.e(mTag, "Error in getService() for " + name); 192 } 193 } 194 createTerminals()195 private void createTerminals() { 196 // Check for all SE HAL implementations 197 addTerminals(ESE_TERMINAL); 198 addTerminals(UICC_TERMINAL); 199 } 200 refreshUiccTerminals(int activeSimCount)201 private void refreshUiccTerminals(int activeSimCount) { 202 String name = null; 203 synchronized (this) { 204 if (activeSimCount < mActiveSimCount) { 205 // Remove non-supported UICC terminals 206 for (int i = activeSimCount + 1; i <= mActiveSimCount; i++) { 207 name = UICC_TERMINAL + Integer.toString(i); 208 Terminal terminal = mTerminals.get(name); 209 if (terminal != null) { 210 terminal.closeChannels(); 211 terminal.close(); 212 } 213 mTerminals.remove(name); 214 Log.i(mTag, name + " is removed from available Terminals"); 215 } 216 mActiveSimCount = activeSimCount; 217 } else if (activeSimCount > mActiveSimCount) { 218 // Try to initialize new UICC terminals 219 addTerminals(UICC_TERMINAL); 220 } 221 } 222 } 223 getPackageNameFromCallingUid(int uid)224 private String getPackageNameFromCallingUid(int uid) { 225 PackageManager packageManager = getPackageManager(); 226 if (packageManager != null) { 227 String[] packageName = packageManager.getPackagesForUid(uid); 228 if (packageName != null && packageName.length > 0) { 229 return packageName[0]; 230 } 231 } 232 throw new AccessControlException("PackageName can not be determined"); 233 } 234 235 final class SecureElementSession extends ISecureElementSession.Stub { 236 237 private final SecureElementReader mReader; 238 /** List of open channels in use of by this client. */ 239 private final List<Channel> mChannels = new ArrayList<>(); 240 private final Object mLock = new Object(); 241 private boolean mIsClosed; 242 private byte[] mAtr; 243 SecureElementSession(SecureElementReader reader)244 SecureElementSession(SecureElementReader reader) { 245 if (reader == null) { 246 throw new NullPointerException("SecureElementReader cannot be null"); 247 } 248 mReader = reader; 249 mAtr = mReader.getAtr(); 250 mIsClosed = false; 251 } 252 getReader()253 public ISecureElementReader getReader() throws RemoteException { 254 return mReader; 255 } 256 257 @Override getAtr()258 public byte[] getAtr() throws RemoteException { 259 return mAtr; 260 } 261 262 @Override close()263 public void close() throws RemoteException { 264 closeChannels(); 265 mReader.removeSession(this); 266 synchronized (mLock) { 267 mIsClosed = true; 268 } 269 } 270 removeChannel(Channel channel)271 void removeChannel(Channel channel) { 272 synchronized (mLock) { 273 if (mChannels != null) { 274 mChannels.remove(channel); 275 } 276 } 277 } 278 279 @Override closeChannels()280 public void closeChannels() throws RemoteException { 281 synchronized (mLock) { 282 while (mChannels.size() > 0) { 283 try { 284 mChannels.get(0).close(); 285 } catch (Exception ignore) { 286 Log.e(mTag, "SecureElementSession Channel - close Exception " 287 + ignore.getMessage()); 288 } 289 } 290 } 291 } 292 293 @Override isClosed()294 public boolean isClosed() throws RemoteException { 295 synchronized (mLock) { 296 return mIsClosed; 297 } 298 } 299 300 @Override openBasicChannel(byte[] aid, byte p2, ISecureElementListener listener)301 public ISecureElementChannel openBasicChannel(byte[] aid, byte p2, 302 ISecureElementListener listener) throws RemoteException { 303 if (DEBUG) { 304 Log.i(mTag, "openBasicChannel() AID = " 305 + ByteArrayConverter.byteArrayToHexString(aid) + ", P2 = " + p2); 306 } 307 if (isClosed()) { 308 throw new IllegalStateException("Session is closed"); 309 } else if (listener == null) { 310 throw new NullPointerException("listener must not be null"); 311 } else if ((p2 != 0x00) && (p2 != 0x04) && (p2 != 0x08) 312 && (p2 != (byte) 0x0C)) { 313 throw new UnsupportedOperationException("p2 not supported: " 314 + String.format("%02x ", p2 & 0xFF)); 315 } 316 317 String packageName = getPackageNameFromCallingUid(Binder.getCallingUid()); 318 Channel channel = null; 319 320 try { 321 channel = mReader.getTerminal().openBasicChannel(this, aid, p2, listener, 322 packageName, Binder.getCallingPid()); 323 } catch (IOException e) { 324 throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage()); 325 } catch (NoSuchElementException e) { 326 throw new ServiceSpecificException(SEService.NO_SUCH_ELEMENT_ERROR, e.getMessage()); 327 } 328 329 if (channel == null) { 330 Log.i(mTag, "OpenBasicChannel() - returning null"); 331 return null; 332 } 333 Log.i(mTag, "Open basic channel success. Channel: " 334 + channel.getChannelNumber()); 335 336 synchronized (mLock) { 337 mChannels.add(channel); 338 } 339 return channel.new SecureElementChannel(); 340 } 341 342 @Override openLogicalChannel(byte[] aid, byte p2, ISecureElementListener listener)343 public ISecureElementChannel openLogicalChannel(byte[] aid, byte p2, 344 ISecureElementListener listener) throws RemoteException { 345 if (DEBUG) { 346 Log.i(mTag, "openLogicalChannel() AID = " 347 + ByteArrayConverter.byteArrayToHexString(aid) + ", P2 = " + p2); 348 } 349 if (isClosed()) { 350 throw new IllegalStateException("Session is closed"); 351 } else if (listener == null) { 352 throw new NullPointerException("listener must not be null"); 353 } else if ((p2 != 0x00) && (p2 != 0x04) && (p2 != 0x08) 354 && (p2 != (byte) 0x0C)) { 355 throw new UnsupportedOperationException("p2 not supported: " 356 + String.format("%02x ", p2 & 0xFF)); 357 } 358 359 String packageName = getPackageNameFromCallingUid(Binder.getCallingUid()); 360 Channel channel = null; 361 362 try { 363 channel = mReader.getTerminal().openLogicalChannel(this, aid, p2, listener, 364 packageName, Binder.getCallingPid()); 365 } catch (IOException e) { 366 throw new ServiceSpecificException(SEService.IO_ERROR, e.getMessage()); 367 } catch (NoSuchElementException e) { 368 throw new ServiceSpecificException(SEService.NO_SUCH_ELEMENT_ERROR, e.getMessage()); 369 } 370 371 if (channel == null) { 372 Log.i(mTag, "openLogicalChannel() - returning null"); 373 return null; 374 } 375 Log.i(mTag, "openLogicalChannel() Success. Channel: " 376 + channel.getChannelNumber()); 377 378 synchronized (mLock) { 379 mChannels.add(channel); 380 } 381 return channel.new SecureElementChannel(); 382 } 383 } 384 385 private final BroadcastReceiver mMultiSimConfigChangedReceiver = new BroadcastReceiver() { 386 @Override 387 public void onReceive(Context context, Intent intent) { 388 String action = intent.getAction(); 389 if (action.equals(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED)) { 390 int activeSimCount = 391 intent.getIntExtra(TelephonyManager.EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 1); 392 Log.i(mTag, "received action MultiSimConfigChanged. Refresh UICC terminals"); 393 Log.i(mTag, "Current ActiveSimCount:" + activeSimCount 394 + ". Previous ActiveSimCount:" + mActiveSimCount); 395 396 // Check for any change to UICC SE HAL implementations 397 refreshUiccTerminals(activeSimCount); 398 } 399 } 400 }; 401 } 402