NfcService.java revision 95b352ec03226adf812d63e6fee568b1a4581021
1/* 2 * Copyright (C) 2010 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 17package com.android.nfc; 18 19import com.android.internal.nfc.LlcpServiceSocket; 20import com.android.internal.nfc.LlcpSocket; 21import com.android.nfc.RegisteredComponentCache.ComponentInfo; 22import com.android.nfc.ndefpush.NdefPushClient; 23import com.android.nfc.ndefpush.NdefPushServer; 24import com.android.nfc3.R; 25 26import android.app.Activity; 27import android.app.ActivityManagerNative; 28import android.app.Application; 29import android.app.IActivityManager; 30import android.app.PendingIntent; 31import android.app.PendingIntent.CanceledException; 32import android.app.StatusBarManager; 33import android.content.ActivityNotFoundException; 34import android.content.BroadcastReceiver; 35import android.content.ComponentName; 36import android.content.Context; 37import android.content.Intent; 38import android.content.IntentFilter; 39import android.content.SharedPreferences; 40import android.content.pm.PackageManager; 41import android.content.pm.ResolveInfo; 42import android.net.Uri; 43import android.nfc.ApduList; 44import android.nfc.ErrorCodes; 45import android.nfc.FormatException; 46import android.nfc.ILlcpConnectionlessSocket; 47import android.nfc.ILlcpServiceSocket; 48import android.nfc.ILlcpSocket; 49import android.nfc.INfcAdapter; 50import android.nfc.INfcAdapterExtras; 51import android.nfc.INfcTag; 52import android.nfc.IP2pInitiator; 53import android.nfc.IP2pTarget; 54import android.nfc.LlcpPacket; 55import android.nfc.NdefMessage; 56import android.nfc.NdefRecord; 57import android.nfc.NfcAdapter; 58import android.nfc.Tag; 59import android.nfc.TechListParcel; 60import android.nfc.TransceiveResult; 61import android.os.AsyncTask; 62import android.os.Bundle; 63import android.os.Handler; 64import android.os.IBinder; 65import android.os.Message; 66import android.os.PowerManager; 67import android.os.RemoteException; 68import android.os.ServiceManager; 69import android.util.Log; 70 71import java.io.ByteArrayOutputStream; 72import java.io.DataInputStream; 73import java.io.DataOutputStream; 74import java.io.FileInputStream; 75import java.io.FileNotFoundException; 76import java.io.FileOutputStream; 77import java.io.IOException; 78import java.nio.charset.Charsets; 79import java.util.ArrayList; 80import java.util.Arrays; 81import java.util.HashMap; 82import java.util.Iterator; 83import java.util.List; 84 85public class NfcService extends Application { 86 private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION"; 87 88 static final boolean DBG = false; 89 90 private static final String MY_TAG_FILE_NAME = "mytag"; 91 private static final String SE_RESET_SCRIPT_FILE_NAME = "/system/etc/se-reset-script"; 92 93 static { 94 System.loadLibrary("nfc_jni"); 95 } 96 97 /** 98 * NFC Forum "URI Record Type Definition" 99 * 100 * This is a mapping of "URI Identifier Codes" to URI string prefixes, 101 * per section 3.2.2 of the NFC Forum URI Record Type Definition document. 102 */ 103 private static final String[] URI_PREFIX_MAP = new String[] { 104 "", // 0x00 105 "http://www.", // 0x01 106 "https://www.", // 0x02 107 "http://", // 0x03 108 "https://", // 0x04 109 "tel:", // 0x05 110 "mailto:", // 0x06 111 "ftp://anonymous:anonymous@", // 0x07 112 "ftp://ftp.", // 0x08 113 "ftps://", // 0x09 114 "sftp://", // 0x0A 115 "smb://", // 0x0B 116 "nfs://", // 0x0C 117 "ftp://", // 0x0D 118 "dav://", // 0x0E 119 "news:", // 0x0F 120 "telnet://", // 0x10 121 "imap:", // 0x11 122 "rtsp://", // 0x12 123 "urn:", // 0x13 124 "pop:", // 0x14 125 "sip:", // 0x15 126 "sips:", // 0x16 127 "tftp:", // 0x17 128 "btspp://", // 0x18 129 "btl2cap://", // 0x19 130 "btgoep://", // 0x1A 131 "tcpobex://", // 0x1B 132 "irdaobex://", // 0x1C 133 "file://", // 0x1D 134 "urn:epc:id:", // 0x1E 135 "urn:epc:tag:", // 0x1F 136 "urn:epc:pat:", // 0x20 137 "urn:epc:raw:", // 0x21 138 "urn:epc:", // 0x22 139 }; 140 141 public static final String SERVICE_NAME = "nfc"; 142 143 private static final String TAG = "NfcService"; 144 145 private static final String NFC_PERM = android.Manifest.permission.NFC; 146 private static final String NFC_PERM_ERROR = "NFC permission required"; 147 private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS; 148 private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required"; 149 private static final String NFCEE_ADMIN_PERM = "com.android.nfc.permission.NFCEE_ADMIN"; 150 private static final String NFCEE_ADMIN_PERM_ERROR = "NFCEE_ADMIN permission required"; 151 152 private static final String PREF = "NfcServicePrefs"; 153 154 private static final String PREF_NFC_ON = "nfc_on"; 155 private static final boolean NFC_ON_DEFAULT = true; 156 157 private static final String PREF_FIRST_BOOT = "first_boot"; 158 159 private static final String PREF_LLCP_LTO = "llcp_lto"; 160 private static final int LLCP_LTO_DEFAULT = 150; 161 private static final int LLCP_LTO_MAX = 255; 162 163 /** Maximum Information Unit */ 164 private static final String PREF_LLCP_MIU = "llcp_miu"; 165 private static final int LLCP_MIU_DEFAULT = 128; 166 private static final int LLCP_MIU_MAX = 2176; 167 168 /** Well Known Service List */ 169 private static final String PREF_LLCP_WKS = "llcp_wks"; 170 private static final int LLCP_WKS_DEFAULT = 1; 171 private static final int LLCP_WKS_MAX = 15; 172 173 private static final String PREF_LLCP_OPT = "llcp_opt"; 174 private static final int LLCP_OPT_DEFAULT = 0; 175 private static final int LLCP_OPT_MAX = 3; 176 177 private static final String PREF_DISCOVERY_A = "discovery_a"; 178 private static final boolean DISCOVERY_A_DEFAULT = true; 179 180 private static final String PREF_DISCOVERY_B = "discovery_b"; 181 private static final boolean DISCOVERY_B_DEFAULT = true; 182 183 private static final String PREF_DISCOVERY_F = "discovery_f"; 184 private static final boolean DISCOVERY_F_DEFAULT = true; 185 186 private static final String PREF_DISCOVERY_15693 = "discovery_15693"; 187 private static final boolean DISCOVERY_15693_DEFAULT = true; 188 189 private static final String PREF_DISCOVERY_NFCIP = "discovery_nfcip"; 190 private static final boolean DISCOVERY_NFCIP_DEFAULT = true; 191 192 /** NFC Reader Discovery mode for enableDiscovery() */ 193 private static final int DISCOVERY_MODE_READER = 0; 194 195 private static final int PROPERTY_LLCP_LTO = 0; 196 private static final String PROPERTY_LLCP_LTO_VALUE = "llcp.lto"; 197 private static final int PROPERTY_LLCP_MIU = 1; 198 private static final String PROPERTY_LLCP_MIU_VALUE = "llcp.miu"; 199 private static final int PROPERTY_LLCP_WKS = 2; 200 private static final String PROPERTY_LLCP_WKS_VALUE = "llcp.wks"; 201 private static final int PROPERTY_LLCP_OPT = 3; 202 private static final String PROPERTY_LLCP_OPT_VALUE = "llcp.opt"; 203 private static final int PROPERTY_NFC_DISCOVERY_A = 4; 204 private static final String PROPERTY_NFC_DISCOVERY_A_VALUE = "discovery.iso14443A"; 205 private static final int PROPERTY_NFC_DISCOVERY_B = 5; 206 private static final String PROPERTY_NFC_DISCOVERY_B_VALUE = "discovery.iso14443B"; 207 private static final int PROPERTY_NFC_DISCOVERY_F = 6; 208 private static final String PROPERTY_NFC_DISCOVERY_F_VALUE = "discovery.felica"; 209 private static final int PROPERTY_NFC_DISCOVERY_15693 = 7; 210 private static final String PROPERTY_NFC_DISCOVERY_15693_VALUE = "discovery.iso15693"; 211 private static final int PROPERTY_NFC_DISCOVERY_NFCIP = 8; 212 private static final String PROPERTY_NFC_DISCOVERY_NFCIP_VALUE = "discovery.nfcip"; 213 214 static final int MSG_NDEF_TAG = 0; 215 static final int MSG_CARD_EMULATION = 1; 216 static final int MSG_LLCP_LINK_ACTIVATION = 2; 217 static final int MSG_LLCP_LINK_DEACTIVATED = 3; 218 static final int MSG_TARGET_DESELECTED = 4; 219 static final int MSG_SHOW_MY_TAG_ICON = 5; 220 static final int MSG_HIDE_MY_TAG_ICON = 6; 221 static final int MSG_MOCK_NDEF = 7; 222 static final int MSG_SE_FIELD_ACTIVATED = 8; 223 static final int MSG_SE_FIELD_DEACTIVATED = 9; 224 225 // Copied from com.android.nfc_extras to avoid library dependency 226 // Must keep in sync with com.android.nfc_extras 227 static final int ROUTE_OFF = 1; 228 static final int ROUTE_ON_WHEN_SCREEN_ON = 2; 229 public static final String ACTION_RF_FIELD_ON_DETECTED = 230 "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED"; 231 public static final String ACTION_RF_FIELD_OFF_DETECTED = 232 "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED"; 233 public static final String ACTION_AID_SELECTED = 234 "com.android.nfc_extras.action.AID_SELECTED"; 235 public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID"; 236 237 // Locked on mNfcAdapter 238 PendingIntent mDispatchOverrideIntent; 239 IntentFilter[] mDispatchOverrideFilters; 240 String[][] mDispatchOverrideTechLists; 241 242 // TODO: none of these appear to be synchronized but are 243 // read/written from different threads (notably Binder threads)... 244 private int mGeneratedSocketHandle = 0; 245 private volatile boolean mIsNfcEnabled = false; 246 private boolean mIsDiscoveryOn = false; 247 248 // NFC Execution Environment 249 // fields below are protected by this 250 private static final int SECURE_ELEMENT_ID = 11259375; //TODO: remove hard-coded value 251 private NativeNfcSecureElement mSecureElement; 252 private OpenSecureElement mOpenEe; // null when EE closed 253 private int mEeRoutingState; // contactless interface routing 254 255 // fields below are used in multiple threads and protected by synchronized(this) 256 private final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>(); 257 private final HashMap<Integer, Object> mSocketMap = new HashMap<Integer, Object>(); 258 private boolean mScreenOn; 259 private String mSePackageName; 260 261 // fields below are final after onCreate() 262 Context mContext; 263 private NativeNfcManager mManager; 264 private SharedPreferences mPrefs; 265 private SharedPreferences.Editor mPrefsEditor; 266 private PowerManager.WakeLock mWakeLock; 267 private IActivityManager mIActivityManager; 268 NdefPushClient mNdefPushClient; 269 NdefPushServer mNdefPushServer; 270 RegisteredComponentCache mTechListFilters; 271 272 private static NfcService sService; 273 274 public static void enforceAdminPerm(Context context) { 275 int admin = context.checkCallingOrSelfPermission(ADMIN_PERM); 276 int nfcee = context.checkCallingOrSelfPermission(NFCEE_ADMIN_PERM); 277 if (admin != PackageManager.PERMISSION_GRANTED 278 && nfcee != PackageManager.PERMISSION_GRANTED) { 279 throw new SecurityException(ADMIN_PERM_ERROR); 280 } 281 } 282 283 public static void enforceNfceeAdminPerm(Context context) { 284 context.enforceCallingOrSelfPermission(NFCEE_ADMIN_PERM, NFCEE_ADMIN_PERM_ERROR); 285 } 286 287 public static NfcService getInstance() { 288 return sService; 289 } 290 291 @Override 292 public void onCreate() { 293 super.onCreate(); 294 295 Log.i(TAG, "Starting NFC service"); 296 297 sService = this; 298 299 mContext = this; 300 mManager = new NativeNfcManager(mContext, this); 301 mManager.initializeNativeStructure(); 302 303 mNdefPushClient = new NdefPushClient(this); 304 mNdefPushServer = new NdefPushServer(); 305 306 mTechListFilters = new RegisteredComponentCache(this, 307 NfcAdapter.ACTION_TECH_DISCOVERED, NfcAdapter.ACTION_TECH_DISCOVERED); 308 309 mSecureElement = new NativeNfcSecureElement(); 310 311 mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); 312 mPrefsEditor = mPrefs.edit(); 313 314 mIsNfcEnabled = false; // real preference read later 315 316 PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); 317 mScreenOn = pm.isScreenOn(); 318 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService"); 319 320 mIActivityManager = ActivityManagerNative.getDefault(); 321 322 ServiceManager.addService(SERVICE_NAME, mNfcAdapter); 323 324 IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION); 325 filter.addAction(Intent.ACTION_SCREEN_OFF); 326 filter.addAction(Intent.ACTION_SCREEN_ON); 327 filter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION); 328 mContext.registerReceiver(mReceiver, filter); 329 330 filter = new IntentFilter(); 331 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 332 filter.addDataScheme("package"); 333 334 mContext.registerReceiver(mReceiver, filter); 335 336 Thread t = new Thread() { 337 @Override 338 public void run() { 339 boolean nfc_on = mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT); 340 if (nfc_on) { 341 _enable(false); 342 } 343 resetSeOnFirstBoot(); 344 } 345 }; 346 t.start(); 347 } 348 349 @Override 350 public void onTerminate() { 351 super.onTerminate(); 352 // NFC application is persistent, it should not be destroyed by framework 353 Log.wtf(TAG, "NFC service is under attack!"); 354 } 355 356 private final INfcAdapter.Stub mNfcAdapter = new INfcAdapter.Stub() { 357 /** Protected by "this" */ 358 NdefMessage mLocalMessage = null; 359 360 @Override 361 public boolean enable() throws RemoteException { 362 NfcService.enforceAdminPerm(mContext); 363 364 boolean isSuccess = false; 365 boolean previouslyEnabled = isEnabled(); 366 if (!previouslyEnabled) { 367 reset(); 368 isSuccess = _enable(previouslyEnabled); 369 } 370 return isSuccess; 371 } 372 373 @Override 374 public boolean disable() throws RemoteException { 375 boolean isSuccess = false; 376 NfcService.enforceAdminPerm(mContext); 377 boolean previouslyEnabled = isEnabled(); 378 if (DBG) Log.d(TAG, "Disabling NFC. previous=" + previouslyEnabled); 379 380 if (previouslyEnabled) { 381 isSuccess = _disable(previouslyEnabled); 382 } 383 return isSuccess; 384 } 385 386 @Override 387 public void enableForegroundDispatch(ComponentName activity, PendingIntent intent, 388 IntentFilter[] filters, TechListParcel techListsParcel) { 389 // Permission check 390 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 391 392 // Argument validation 393 if (activity == null || intent == null) { 394 throw new IllegalArgumentException(); 395 } 396 397 // Validate the IntentFilters 398 if (filters != null) { 399 if (filters.length == 0) { 400 filters = null; 401 } else { 402 for (IntentFilter filter : filters) { 403 if (filter == null) { 404 throw new IllegalArgumentException("null IntentFilter"); 405 } 406 } 407 } 408 } 409 410 // Validate the tech lists 411 String[][] techLists = null; 412 if (techListsParcel != null) { 413 techLists = techListsParcel.getTechLists(); 414 } 415 416 synchronized (this) { 417 if (mDispatchOverrideIntent != null) { 418 Log.e(TAG, "Replacing active dispatch overrides"); 419 } 420 mDispatchOverrideIntent = intent; 421 mDispatchOverrideFilters = filters; 422 mDispatchOverrideTechLists = techLists; 423 } 424 } 425 426 @Override 427 public void disableForegroundDispatch(ComponentName activity) { 428 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 429 synchronized (this) { 430 if (mDispatchOverrideIntent == null) { 431 Log.e(TAG, "No active foreground dispatching"); 432 } 433 mDispatchOverrideIntent = null; 434 mDispatchOverrideFilters = null; 435 } 436 } 437 438 @Override 439 public void enableForegroundNdefPush(ComponentName activity, NdefMessage msg) { 440 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 441 if (activity == null || msg == null) { 442 throw new IllegalArgumentException(); 443 } 444 if (mNdefPushClient.setForegroundMessage(msg)) { 445 Log.e(TAG, "Replacing active NDEF push message"); 446 } 447 } 448 449 @Override 450 public void disableForegroundNdefPush(ComponentName activity) { 451 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 452 if (!mNdefPushClient.setForegroundMessage(null)) { 453 Log.e(TAG, "No active foreground NDEF push message"); 454 } 455 } 456 457 @Override 458 public int createLlcpConnectionlessSocket(int sap) throws RemoteException { 459 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 460 461 // Check if NFC is enabled 462 if (!mIsNfcEnabled) { 463 return ErrorCodes.ERROR_NOT_INITIALIZED; 464 } 465 466 /* Check SAP is not already used */ 467 468 /* Store the socket handle */ 469 int sockeHandle = mGeneratedSocketHandle; 470 NativeLlcpConnectionlessSocket socket; 471 472 socket = mManager.doCreateLlcpConnectionlessSocket(sap); 473 if (socket != null) { 474 synchronized(NfcService.this) { 475 /* update socket handle generation */ 476 mGeneratedSocketHandle++; 477 478 /* Add the socket into the socket map */ 479 mSocketMap.put(mGeneratedSocketHandle, socket); 480 return mGeneratedSocketHandle; 481 } 482 } else { 483 /* Get Error Status */ 484 int errorStatus = mManager.doGetLastError(); 485 486 switch (errorStatus) { 487 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 488 return ErrorCodes.ERROR_BUFFER_TO_SMALL; 489 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 490 return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES; 491 default: 492 return ErrorCodes.ERROR_SOCKET_CREATION; 493 } 494 } 495 } 496 497 @Override 498 public int createLlcpServiceSocket(int sap, String sn, int miu, int rw, int linearBufferLength) 499 throws RemoteException { 500 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 501 502 // Check if NFC is enabled 503 if (!mIsNfcEnabled) { 504 return ErrorCodes.ERROR_NOT_INITIALIZED; 505 } 506 507 NativeLlcpServiceSocket socket; 508 509 socket = mManager.doCreateLlcpServiceSocket(sap, sn, miu, rw, linearBufferLength); 510 if (socket != null) { 511 synchronized(NfcService.this) { 512 /* update socket handle generation */ 513 mGeneratedSocketHandle++; 514 515 /* Add the socket into the socket map */ 516 mSocketMap.put(mGeneratedSocketHandle, socket); 517 return mGeneratedSocketHandle; 518 } 519 } else { 520 /* Get Error Status */ 521 int errorStatus = mManager.doGetLastError(); 522 523 switch (errorStatus) { 524 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 525 return ErrorCodes.ERROR_BUFFER_TO_SMALL; 526 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 527 return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES; 528 default: 529 return ErrorCodes.ERROR_SOCKET_CREATION; 530 } 531 } 532 } 533 534 @Override 535 public int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength) 536 throws RemoteException { 537 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 538 539 // Check if NFC is enabled 540 if (!mIsNfcEnabled) { 541 return ErrorCodes.ERROR_NOT_INITIALIZED; 542 } 543 544 if (DBG) Log.d(TAG, "creating llcp socket"); 545 NativeLlcpSocket socket; 546 547 socket = mManager.doCreateLlcpSocket(sap, miu, rw, linearBufferLength); 548 549 if (socket != null) { 550 synchronized(NfcService.this) { 551 /* update socket handle generation */ 552 mGeneratedSocketHandle++; 553 554 /* Add the socket into the socket map */ 555 mSocketMap.put(mGeneratedSocketHandle, socket); 556 return mGeneratedSocketHandle; 557 } 558 } else { 559 /* Get Error Status */ 560 int errorStatus = mManager.doGetLastError(); 561 562 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(errorStatus)); 563 564 switch (errorStatus) { 565 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 566 return ErrorCodes.ERROR_BUFFER_TO_SMALL; 567 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 568 return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES; 569 default: 570 return ErrorCodes.ERROR_SOCKET_CREATION; 571 } 572 } 573 } 574 575 @Override 576 public ILlcpConnectionlessSocket getLlcpConnectionlessInterface() throws RemoteException { 577 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 578 return mLlcpConnectionlessSocketService; 579 } 580 581 @Override 582 public ILlcpSocket getLlcpInterface() throws RemoteException { 583 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 584 return mLlcpSocket; 585 } 586 587 @Override 588 public ILlcpServiceSocket getLlcpServiceInterface() throws RemoteException { 589 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 590 return mLlcpServerSocketService; 591 } 592 593 @Override 594 public INfcTag getNfcTagInterface() throws RemoteException { 595 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 596 return mNfcTagService; 597 } 598 599 @Override 600 public IP2pInitiator getP2pInitiatorInterface() throws RemoteException { 601 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 602 return mP2pInitiatorService; 603 } 604 605 @Override 606 public IP2pTarget getP2pTargetInterface() throws RemoteException { 607 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 608 return mP2pTargetService; 609 } 610 611 @Override 612 public INfcAdapterExtras getNfcAdapterExtrasInterface() { 613 NfcService.enforceNfceeAdminPerm(mContext); 614 return mExtrasService; 615 } 616 617 @Override 618 public String getProperties(String param) throws RemoteException { 619 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 620 621 if (param == null) { 622 return null; 623 } 624 625 if (param.equals(PROPERTY_LLCP_LTO_VALUE)) { 626 return Integer.toString(mPrefs.getInt(PREF_LLCP_LTO, LLCP_LTO_DEFAULT)); 627 } else if (param.equals(PROPERTY_LLCP_MIU_VALUE)) { 628 return Integer.toString(mPrefs.getInt(PREF_LLCP_MIU, LLCP_MIU_DEFAULT)); 629 } else if (param.equals(PROPERTY_LLCP_WKS_VALUE)) { 630 return Integer.toString(mPrefs.getInt(PREF_LLCP_WKS, LLCP_WKS_DEFAULT)); 631 } else if (param.equals(PROPERTY_LLCP_OPT_VALUE)) { 632 return Integer.toString(mPrefs.getInt(PREF_LLCP_OPT, LLCP_OPT_DEFAULT)); 633 } else if (param.equals(PROPERTY_NFC_DISCOVERY_A_VALUE)) { 634 return Boolean.toString(mPrefs.getBoolean(PREF_DISCOVERY_A, DISCOVERY_A_DEFAULT)); 635 } else if (param.equals(PROPERTY_NFC_DISCOVERY_B_VALUE)) { 636 return Boolean.toString(mPrefs.getBoolean(PREF_DISCOVERY_B, DISCOVERY_B_DEFAULT)); 637 } else if (param.equals(PROPERTY_NFC_DISCOVERY_F_VALUE)) { 638 return Boolean.toString(mPrefs.getBoolean(PREF_DISCOVERY_F, DISCOVERY_F_DEFAULT)); 639 } else if (param.equals(PROPERTY_NFC_DISCOVERY_NFCIP_VALUE)) { 640 return Boolean.toString(mPrefs.getBoolean(PREF_DISCOVERY_NFCIP, DISCOVERY_NFCIP_DEFAULT)); 641 } else if (param.equals(PROPERTY_NFC_DISCOVERY_15693_VALUE)) { 642 return Boolean.toString(mPrefs.getBoolean(PREF_DISCOVERY_15693, DISCOVERY_15693_DEFAULT)); 643 } else { 644 return "Unknown property"; 645 } 646 } 647 648 @Override 649 public boolean isEnabled() throws RemoteException { 650 return mIsNfcEnabled; 651 } 652 653 @Override 654 public int setProperties(String param, String value) throws RemoteException { 655 NfcService.enforceAdminPerm(mContext); 656 657 if (isEnabled()) { 658 return ErrorCodes.ERROR_NFC_ON; 659 } 660 661 int val; 662 663 /* Check params validity */ 664 if (param == null || value == null) { 665 return ErrorCodes.ERROR_INVALID_PARAM; 666 } 667 668 if (param.equals(PROPERTY_LLCP_LTO_VALUE)) { 669 val = Integer.parseInt(value); 670 671 /* Check params */ 672 if (val > LLCP_LTO_MAX) 673 return ErrorCodes.ERROR_INVALID_PARAM; 674 675 /* Store value */ 676 mPrefsEditor.putInt(PREF_LLCP_LTO, val); 677 mPrefsEditor.apply(); 678 679 /* Update JNI */ 680 mManager.doSetProperties(PROPERTY_LLCP_LTO, val); 681 682 } else if (param.equals(PROPERTY_LLCP_MIU_VALUE)) { 683 val = Integer.parseInt(value); 684 685 /* Check params */ 686 if ((val < LLCP_MIU_DEFAULT) || (val > LLCP_MIU_MAX)) 687 return ErrorCodes.ERROR_INVALID_PARAM; 688 689 /* Store value */ 690 mPrefsEditor.putInt(PREF_LLCP_MIU, val); 691 mPrefsEditor.apply(); 692 693 /* Update JNI */ 694 mManager.doSetProperties(PROPERTY_LLCP_MIU, val); 695 696 } else if (param.equals(PROPERTY_LLCP_WKS_VALUE)) { 697 val = Integer.parseInt(value); 698 699 /* Check params */ 700 if (val > LLCP_WKS_MAX) 701 return ErrorCodes.ERROR_INVALID_PARAM; 702 703 /* Store value */ 704 mPrefsEditor.putInt(PREF_LLCP_WKS, val); 705 mPrefsEditor.apply(); 706 707 /* Update JNI */ 708 mManager.doSetProperties(PROPERTY_LLCP_WKS, val); 709 710 } else if (param.equals(PROPERTY_LLCP_OPT_VALUE)) { 711 val = Integer.parseInt(value); 712 713 /* Check params */ 714 if (val > LLCP_OPT_MAX) 715 return ErrorCodes.ERROR_INVALID_PARAM; 716 717 /* Store value */ 718 mPrefsEditor.putInt(PREF_LLCP_OPT, val); 719 mPrefsEditor.apply(); 720 721 /* Update JNI */ 722 mManager.doSetProperties(PROPERTY_LLCP_OPT, val); 723 724 } else if (param.equals(PROPERTY_NFC_DISCOVERY_A_VALUE)) { 725 boolean b = Boolean.parseBoolean(value); 726 727 /* Store value */ 728 mPrefsEditor.putBoolean(PREF_DISCOVERY_A, b); 729 mPrefsEditor.apply(); 730 731 /* Update JNI */ 732 mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_A, b ? 1 : 0); 733 734 } else if (param.equals(PROPERTY_NFC_DISCOVERY_B_VALUE)) { 735 boolean b = Boolean.parseBoolean(value); 736 737 /* Store value */ 738 mPrefsEditor.putBoolean(PREF_DISCOVERY_B, b); 739 mPrefsEditor.apply(); 740 741 /* Update JNI */ 742 mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_B, b ? 1 : 0); 743 744 } else if (param.equals(PROPERTY_NFC_DISCOVERY_F_VALUE)) { 745 boolean b = Boolean.parseBoolean(value); 746 747 /* Store value */ 748 mPrefsEditor.putBoolean(PREF_DISCOVERY_F, b); 749 mPrefsEditor.apply(); 750 751 /* Update JNI */ 752 mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_F, b ? 1 : 0); 753 754 } else if (param.equals(PROPERTY_NFC_DISCOVERY_15693_VALUE)) { 755 boolean b = Boolean.parseBoolean(value); 756 757 /* Store value */ 758 mPrefsEditor.putBoolean(PREF_DISCOVERY_15693, b); 759 mPrefsEditor.apply(); 760 761 /* Update JNI */ 762 mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_15693, b ? 1 : 0); 763 764 } else if (param.equals(PROPERTY_NFC_DISCOVERY_NFCIP_VALUE)) { 765 boolean b = Boolean.parseBoolean(value); 766 767 /* Store value */ 768 mPrefsEditor.putBoolean(PREF_DISCOVERY_NFCIP, b); 769 mPrefsEditor.apply(); 770 771 /* Update JNI */ 772 mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_NFCIP, b ? 1 : 0); 773 774 } else { 775 return ErrorCodes.ERROR_INVALID_PARAM; 776 } 777 778 return ErrorCodes.SUCCESS; 779 } 780 781 @Override 782 public NdefMessage localGet() throws RemoteException { 783 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 784 785 synchronized (this) { 786 return mLocalMessage; 787 } 788 } 789 790 @Override 791 public void localSet(NdefMessage message) throws RemoteException { 792 NfcService.enforceAdminPerm(mContext); 793 794 synchronized (this) { 795 mLocalMessage = message; 796 Context context = NfcService.this.getApplicationContext(); 797 798 // Send a message to the UI thread to show or hide the icon so the requests are 799 // serialized and the icon can't get out of sync with reality. 800 if (message != null) { 801 FileOutputStream out = null; 802 803 try { 804 out = context.openFileOutput(MY_TAG_FILE_NAME, Context.MODE_PRIVATE); 805 byte[] bytes = message.toByteArray(); 806 if (bytes.length == 0) { 807 Log.w(TAG, "Setting a empty mytag"); 808 } 809 810 out.write(bytes); 811 } catch (IOException e) { 812 Log.e(TAG, "Could not write mytag file", e); 813 } finally { 814 try { 815 if (out != null) { 816 out.flush(); 817 out.close(); 818 } 819 } catch (IOException e) { 820 // Ignore 821 } 822 } 823 824 // Only show the icon if NFC is enabled. 825 if (mIsNfcEnabled) { 826 sendMessage(MSG_SHOW_MY_TAG_ICON, null); 827 } 828 } else { 829 context.deleteFile(MY_TAG_FILE_NAME); 830 sendMessage(MSG_HIDE_MY_TAG_ICON, null); 831 } 832 } 833 } 834 }; 835 836 private final ILlcpSocket mLlcpSocket = new ILlcpSocket.Stub() { 837 838 private NativeLlcpSocket findSocket(int nativeHandle) { 839 Object socket = NfcService.this.findSocket(nativeHandle); 840 if (!(socket instanceof NativeLlcpSocket)) { 841 return null; 842 } 843 return (NativeLlcpSocket) socket; 844 } 845 846 @Override 847 public int close(int nativeHandle) throws RemoteException { 848 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 849 850 NativeLlcpSocket socket = null; 851 852 // Check if NFC is enabled 853 if (!mIsNfcEnabled) { 854 return ErrorCodes.ERROR_NOT_INITIALIZED; 855 } 856 857 /* find the socket in the hmap */ 858 socket = findSocket(nativeHandle); 859 if (socket != null) { 860 socket.doClose(); 861 /* Remove the socket closed from the hmap */ 862 RemoveSocket(nativeHandle); 863 return ErrorCodes.SUCCESS; 864 } else { 865 return ErrorCodes.ERROR_IO; 866 } 867 } 868 869 @Override 870 public int connect(int nativeHandle, int sap) throws RemoteException { 871 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 872 873 NativeLlcpSocket socket = null; 874 boolean isSuccess = false; 875 876 // Check if NFC is enabled 877 if (!mIsNfcEnabled) { 878 return ErrorCodes.ERROR_NOT_INITIALIZED; 879 } 880 881 /* find the socket in the hmap */ 882 socket = findSocket(nativeHandle); 883 if (socket != null) { 884 isSuccess = socket.doConnect(sap); 885 if (isSuccess) { 886 return ErrorCodes.SUCCESS; 887 } else { 888 return ErrorCodes.ERROR_IO; 889 } 890 } else { 891 return ErrorCodes.ERROR_IO; 892 } 893 894 } 895 896 @Override 897 public int connectByName(int nativeHandle, String sn) throws RemoteException { 898 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 899 900 NativeLlcpSocket socket = null; 901 boolean isSuccess = false; 902 903 // Check if NFC is enabled 904 if (!mIsNfcEnabled) { 905 return ErrorCodes.ERROR_NOT_INITIALIZED; 906 } 907 908 /* find the socket in the hmap */ 909 socket = findSocket(nativeHandle); 910 if (socket != null) { 911 isSuccess = socket.doConnectBy(sn); 912 if (isSuccess) { 913 return ErrorCodes.SUCCESS; 914 } else { 915 return ErrorCodes.ERROR_IO; 916 } 917 } else { 918 return ErrorCodes.ERROR_IO; 919 } 920 921 } 922 923 @Override 924 public int getLocalSap(int nativeHandle) throws RemoteException { 925 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 926 927 NativeLlcpSocket socket = null; 928 929 // Check if NFC is enabled 930 if (!mIsNfcEnabled) { 931 return ErrorCodes.ERROR_NOT_INITIALIZED; 932 } 933 934 /* find the socket in the hmap */ 935 socket = findSocket(nativeHandle); 936 if (socket != null) { 937 return socket.getSap(); 938 } else { 939 return 0; 940 } 941 } 942 943 @Override 944 public int getLocalSocketMiu(int nativeHandle) throws RemoteException { 945 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 946 947 NativeLlcpSocket socket = null; 948 949 // Check if NFC is enabled 950 if (!mIsNfcEnabled) { 951 return ErrorCodes.ERROR_NOT_INITIALIZED; 952 } 953 954 /* find the socket in the hmap */ 955 socket = findSocket(nativeHandle); 956 if (socket != null) { 957 return socket.getMiu(); 958 } else { 959 return 0; 960 } 961 } 962 963 @Override 964 public int getLocalSocketRw(int nativeHandle) throws RemoteException { 965 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 966 967 NativeLlcpSocket socket = null; 968 969 // Check if NFC is enabled 970 if (!mIsNfcEnabled) { 971 return ErrorCodes.ERROR_NOT_INITIALIZED; 972 } 973 974 /* find the socket in the hmap */ 975 socket = findSocket(nativeHandle); 976 if (socket != null) { 977 return socket.getRw(); 978 } else { 979 return 0; 980 } 981 } 982 983 @Override 984 public int getRemoteSocketMiu(int nativeHandle) throws RemoteException { 985 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 986 987 NativeLlcpSocket socket = null; 988 989 // Check if NFC is enabled 990 if (!mIsNfcEnabled) { 991 return ErrorCodes.ERROR_NOT_INITIALIZED; 992 } 993 994 /* find the socket in the hmap */ 995 socket = findSocket(nativeHandle); 996 if (socket != null) { 997 if (socket.doGetRemoteSocketMiu() != 0) { 998 return socket.doGetRemoteSocketMiu(); 999 } else { 1000 return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED; 1001 } 1002 } else { 1003 return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED; 1004 } 1005 } 1006 1007 @Override 1008 public int getRemoteSocketRw(int nativeHandle) throws RemoteException { 1009 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1010 1011 NativeLlcpSocket socket = null; 1012 1013 // Check if NFC is enabled 1014 if (!mIsNfcEnabled) { 1015 return ErrorCodes.ERROR_NOT_INITIALIZED; 1016 } 1017 1018 /* find the socket in the hmap */ 1019 socket = findSocket(nativeHandle); 1020 if (socket != null) { 1021 if (socket.doGetRemoteSocketRw() != 0) { 1022 return socket.doGetRemoteSocketRw(); 1023 } else { 1024 return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED; 1025 } 1026 } else { 1027 return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED; 1028 } 1029 } 1030 1031 @Override 1032 public int receive(int nativeHandle, byte[] receiveBuffer) throws RemoteException { 1033 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1034 1035 NativeLlcpSocket socket = null; 1036 1037 // Check if NFC is enabled 1038 if (!mIsNfcEnabled) { 1039 return ErrorCodes.ERROR_NOT_INITIALIZED; 1040 } 1041 1042 /* find the socket in the hmap */ 1043 socket = findSocket(nativeHandle); 1044 if (socket != null) { 1045 return socket.doReceive(receiveBuffer); 1046 } else { 1047 return 0; 1048 } 1049 } 1050 1051 @Override 1052 public int send(int nativeHandle, byte[] data) throws RemoteException { 1053 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1054 1055 NativeLlcpSocket socket = null; 1056 boolean isSuccess = false; 1057 1058 // Check if NFC is enabled 1059 if (!mIsNfcEnabled) { 1060 return ErrorCodes.ERROR_NOT_INITIALIZED; 1061 } 1062 1063 /* find the socket in the hmap */ 1064 socket = findSocket(nativeHandle); 1065 if (socket != null) { 1066 isSuccess = socket.doSend(data); 1067 if (isSuccess) { 1068 return ErrorCodes.SUCCESS; 1069 } else { 1070 return ErrorCodes.ERROR_IO; 1071 } 1072 } else { 1073 return ErrorCodes.ERROR_IO; 1074 } 1075 } 1076 }; 1077 1078 private final ILlcpServiceSocket mLlcpServerSocketService = new ILlcpServiceSocket.Stub() { 1079 1080 private NativeLlcpServiceSocket findSocket(int nativeHandle) { 1081 Object socket = NfcService.this.findSocket(nativeHandle); 1082 if (!(socket instanceof NativeLlcpServiceSocket)) { 1083 return null; 1084 } 1085 return (NativeLlcpServiceSocket) socket; 1086 } 1087 1088 @Override 1089 public int accept(int nativeHandle) throws RemoteException { 1090 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1091 1092 NativeLlcpServiceSocket socket = null; 1093 NativeLlcpSocket clientSocket = null; 1094 1095 // Check if NFC is enabled 1096 if (!mIsNfcEnabled) { 1097 return ErrorCodes.ERROR_NOT_INITIALIZED; 1098 } 1099 1100 /* find the socket in the hmap */ 1101 socket = findSocket(nativeHandle); 1102 if (socket != null) { 1103 clientSocket = socket.doAccept(socket.getMiu(), 1104 socket.getRw(), socket.getLinearBufferLength()); 1105 if (clientSocket != null) { 1106 /* Add the socket into the socket map */ 1107 synchronized(this) { 1108 mGeneratedSocketHandle++; 1109 mSocketMap.put(mGeneratedSocketHandle, clientSocket); 1110 return mGeneratedSocketHandle; 1111 } 1112 } else { 1113 return ErrorCodes.ERROR_IO; 1114 } 1115 } else { 1116 return ErrorCodes.ERROR_IO; 1117 } 1118 } 1119 1120 @Override 1121 public void close(int nativeHandle) throws RemoteException { 1122 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1123 1124 NativeLlcpServiceSocket socket = null; 1125 1126 // Check if NFC is enabled 1127 if (!mIsNfcEnabled) { 1128 return; 1129 } 1130 1131 /* find the socket in the hmap */ 1132 socket = findSocket(nativeHandle); 1133 if (socket != null) { 1134 socket.doClose(); 1135 synchronized (this) { 1136 /* Remove the socket closed from the hmap */ 1137 RemoveSocket(nativeHandle); 1138 } 1139 } 1140 } 1141 }; 1142 1143 private final ILlcpConnectionlessSocket mLlcpConnectionlessSocketService = new ILlcpConnectionlessSocket.Stub() { 1144 1145 private NativeLlcpConnectionlessSocket findSocket(int nativeHandle) { 1146 Object socket = NfcService.this.findSocket(nativeHandle); 1147 if (!(socket instanceof NativeLlcpConnectionlessSocket)) { 1148 return null; 1149 } 1150 return (NativeLlcpConnectionlessSocket) socket; 1151 } 1152 1153 @Override 1154 public void close(int nativeHandle) throws RemoteException { 1155 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1156 1157 NativeLlcpConnectionlessSocket socket = null; 1158 1159 // Check if NFC is enabled 1160 if (!mIsNfcEnabled) { 1161 return; 1162 } 1163 1164 /* find the socket in the hmap */ 1165 socket = findSocket(nativeHandle); 1166 if (socket != null) { 1167 socket.doClose(); 1168 /* Remove the socket closed from the hmap */ 1169 RemoveSocket(nativeHandle); 1170 } 1171 } 1172 1173 @Override 1174 public int getSap(int nativeHandle) throws RemoteException { 1175 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1176 1177 NativeLlcpConnectionlessSocket socket = null; 1178 1179 // Check if NFC is enabled 1180 if (!mIsNfcEnabled) { 1181 return ErrorCodes.ERROR_NOT_INITIALIZED; 1182 } 1183 1184 /* find the socket in the hmap */ 1185 socket = findSocket(nativeHandle); 1186 if (socket != null) { 1187 return socket.getSap(); 1188 } else { 1189 return 0; 1190 } 1191 } 1192 1193 @Override 1194 public LlcpPacket receiveFrom(int nativeHandle) throws RemoteException { 1195 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1196 1197 NativeLlcpConnectionlessSocket socket = null; 1198 LlcpPacket packet; 1199 1200 // Check if NFC is enabled 1201 if (!mIsNfcEnabled) { 1202 return null; 1203 } 1204 1205 /* find the socket in the hmap */ 1206 socket = findSocket(nativeHandle); 1207 if (socket != null) { 1208 packet = socket.doReceiveFrom(socket.getLinkMiu()); 1209 if (packet != null) { 1210 return packet; 1211 } 1212 return null; 1213 } else { 1214 return null; 1215 } 1216 } 1217 1218 @Override 1219 public int sendTo(int nativeHandle, LlcpPacket packet) throws RemoteException { 1220 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1221 1222 NativeLlcpConnectionlessSocket socket = null; 1223 boolean isSuccess = false; 1224 1225 // Check if NFC is enabled 1226 if (!mIsNfcEnabled) { 1227 return ErrorCodes.ERROR_NOT_INITIALIZED; 1228 } 1229 1230 /* find the socket in the hmap */ 1231 socket = findSocket(nativeHandle); 1232 if (socket != null) { 1233 isSuccess = socket.doSendTo(packet.getRemoteSap(), packet.getDataBuffer()); 1234 if (isSuccess) { 1235 return ErrorCodes.SUCCESS; 1236 } else { 1237 return ErrorCodes.ERROR_IO; 1238 } 1239 } else { 1240 return ErrorCodes.ERROR_IO; 1241 } 1242 } 1243 }; 1244 1245 private final INfcTag mNfcTagService = new INfcTag.Stub() { 1246 1247 @Override 1248 public int close(int nativeHandle) throws RemoteException { 1249 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1250 1251 NativeNfcTag tag = null; 1252 1253 // Check if NFC is enabled 1254 if (!mIsNfcEnabled) { 1255 return ErrorCodes.ERROR_NOT_INITIALIZED; 1256 } 1257 1258 /* find the tag in the hmap */ 1259 tag = (NativeNfcTag) findObject(nativeHandle); 1260 if (tag != null) { 1261 /* Remove the device from the hmap */ 1262 unregisterObject(nativeHandle); 1263 tag.disconnect(); 1264 return ErrorCodes.SUCCESS; 1265 } 1266 /* Restart polling loop for notification */ 1267 applyRouting(); 1268 return ErrorCodes.ERROR_DISCONNECT; 1269 } 1270 1271 @Override 1272 public int connect(int nativeHandle, int technology) throws RemoteException { 1273 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1274 1275 NativeNfcTag tag = null; 1276 1277 // Check if NFC is enabled 1278 if (!mIsNfcEnabled) { 1279 return ErrorCodes.ERROR_NOT_INITIALIZED; 1280 } 1281 1282 /* find the tag in the hmap */ 1283 tag = (NativeNfcTag) findObject(nativeHandle); 1284 if (tag == null) { 1285 return ErrorCodes.ERROR_DISCONNECT; 1286 } 1287 1288 // Note that on most tags, all technologies are behind a single 1289 // handle. This means that the connect at the lower levels 1290 // will do nothing, as the tag is already connected to that handle. 1291 if (tag.connect(technology)) { 1292 return ErrorCodes.SUCCESS; 1293 } else { 1294 return ErrorCodes.ERROR_DISCONNECT; 1295 } 1296 } 1297 1298 @Override 1299 public int reconnect(int nativeHandle) throws RemoteException { 1300 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1301 1302 NativeNfcTag tag = null; 1303 1304 // Check if NFC is enabled 1305 if (!mIsNfcEnabled) { 1306 return ErrorCodes.ERROR_NOT_INITIALIZED; 1307 } 1308 1309 /* find the tag in the hmap */ 1310 tag = (NativeNfcTag) findObject(nativeHandle); 1311 if (tag != null) { 1312 if (tag.reconnect()) { 1313 return ErrorCodes.SUCCESS; 1314 } else { 1315 return ErrorCodes.ERROR_DISCONNECT; 1316 } 1317 } 1318 return ErrorCodes.ERROR_DISCONNECT; 1319 } 1320 1321 @Override 1322 public int[] getTechList(int nativeHandle) throws RemoteException { 1323 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1324 1325 // Check if NFC is enabled 1326 if (!mIsNfcEnabled) { 1327 return null; 1328 } 1329 1330 /* find the tag in the hmap */ 1331 NativeNfcTag tag = (NativeNfcTag) findObject(nativeHandle); 1332 if (tag != null) { 1333 return tag.getTechList(); 1334 } 1335 return null; 1336 } 1337 1338 @Override 1339 public byte[] getUid(int nativeHandle) throws RemoteException { 1340 NativeNfcTag tag = null; 1341 byte[] uid; 1342 1343 // Check if NFC is enabled 1344 if (!mIsNfcEnabled) { 1345 return null; 1346 } 1347 1348 /* find the tag in the hmap */ 1349 tag = (NativeNfcTag) findObject(nativeHandle); 1350 if (tag != null) { 1351 uid = tag.getUid(); 1352 return uid; 1353 } 1354 return null; 1355 } 1356 1357 @Override 1358 public boolean isPresent(int nativeHandle) throws RemoteException { 1359 NativeNfcTag tag = null; 1360 1361 // Check if NFC is enabled 1362 if (!mIsNfcEnabled) { 1363 return false; 1364 } 1365 1366 /* find the tag in the hmap */ 1367 tag = (NativeNfcTag) findObject(nativeHandle); 1368 if (tag == null) { 1369 return false; 1370 } 1371 1372 return tag.isPresent(); 1373 } 1374 1375 @Override 1376 public boolean isNdef(int nativeHandle) throws RemoteException { 1377 NativeNfcTag tag = null; 1378 boolean isSuccess = false; 1379 1380 // Check if NFC is enabled 1381 if (!mIsNfcEnabled) { 1382 return isSuccess; 1383 } 1384 1385 /* find the tag in the hmap */ 1386 tag = (NativeNfcTag) findObject(nativeHandle); 1387 int[] ndefInfo = new int[2]; 1388 if (tag != null) { 1389 isSuccess = tag.checkNdef(ndefInfo); 1390 } 1391 return isSuccess; 1392 } 1393 1394 @Override 1395 public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw) 1396 throws RemoteException { 1397 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1398 1399 NativeNfcTag tag = null; 1400 byte[] response; 1401 1402 // Check if NFC is enabled 1403 if (!mIsNfcEnabled) { 1404 return null; 1405 } 1406 1407 /* find the tag in the hmap */ 1408 tag = (NativeNfcTag) findObject(nativeHandle); 1409 if (tag != null) { 1410 int[] targetLost = new int[1]; 1411 response = tag.transceive(data, raw, targetLost); 1412 TransceiveResult transResult = new TransceiveResult( 1413 (response != null) ? true : false, 1414 (targetLost[0] == 1) ? true : false, 1415 response); 1416 return transResult; 1417 } 1418 return null; 1419 } 1420 1421 @Override 1422 public NdefMessage ndefRead(int nativeHandle) throws RemoteException { 1423 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1424 1425 NativeNfcTag tag; 1426 1427 // Check if NFC is enabled 1428 if (!mIsNfcEnabled) { 1429 return null; 1430 } 1431 1432 /* find the tag in the hmap */ 1433 tag = (NativeNfcTag) findObject(nativeHandle); 1434 if (tag != null) { 1435 byte[] buf = tag.read(); 1436 if (buf == null) 1437 return null; 1438 1439 /* Create an NdefMessage */ 1440 try { 1441 return new NdefMessage(buf); 1442 } catch (FormatException e) { 1443 return null; 1444 } 1445 } 1446 return null; 1447 } 1448 1449 @Override 1450 public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException { 1451 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1452 1453 NativeNfcTag tag; 1454 1455 // Check if NFC is enabled 1456 if (!mIsNfcEnabled) { 1457 return ErrorCodes.ERROR_NOT_INITIALIZED; 1458 } 1459 1460 /* find the tag in the hmap */ 1461 tag = (NativeNfcTag) findObject(nativeHandle); 1462 if (tag == null) { 1463 return ErrorCodes.ERROR_IO; 1464 } 1465 1466 if (tag.write(msg.toByteArray())) { 1467 return ErrorCodes.SUCCESS; 1468 } 1469 else { 1470 return ErrorCodes.ERROR_IO; 1471 } 1472 1473 } 1474 1475 @Override 1476 public int getLastError(int nativeHandle) throws RemoteException { 1477 return(mManager.doGetLastError()); 1478 } 1479 1480 @Override 1481 public boolean ndefIsWritable(int nativeHandle) throws RemoteException { 1482 throw new UnsupportedOperationException(); 1483 } 1484 1485 @Override 1486 public int ndefMakeReadOnly(int nativeHandle) throws RemoteException { 1487 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1488 1489 NativeNfcTag tag; 1490 1491 // Check if NFC is enabled 1492 if (!mIsNfcEnabled) { 1493 return ErrorCodes.ERROR_NOT_INITIALIZED; 1494 } 1495 1496 /* find the tag in the hmap */ 1497 tag = (NativeNfcTag) findObject(nativeHandle); 1498 if (tag == null) { 1499 return ErrorCodes.ERROR_IO; 1500 } 1501 1502 if (tag.makeReadonly()) { 1503 return ErrorCodes.SUCCESS; 1504 } 1505 else { 1506 return ErrorCodes.ERROR_IO; 1507 } 1508 } 1509 1510 @Override 1511 public int formatNdef(int nativeHandle, byte[] key) throws RemoteException { 1512 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1513 1514 NativeNfcTag tag; 1515 1516 // Check if NFC is enabled 1517 if (!mIsNfcEnabled) { 1518 return ErrorCodes.ERROR_NOT_INITIALIZED; 1519 } 1520 1521 /* find the tag in the hmap */ 1522 tag = (NativeNfcTag) findObject(nativeHandle); 1523 if (tag == null) { 1524 return ErrorCodes.ERROR_IO; 1525 } 1526 1527 if (tag.formatNdef(key)) { 1528 return ErrorCodes.SUCCESS; 1529 } 1530 else { 1531 return ErrorCodes.ERROR_IO; 1532 } 1533 } 1534 1535 @Override 1536 public void setIsoDepTimeout(int timeout) throws RemoteException { 1537 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1538 1539 mManager.setIsoDepTimeout(timeout); 1540 } 1541 1542 @Override 1543 public void resetIsoDepTimeout() throws RemoteException { 1544 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1545 1546 mManager.resetIsoDepTimeout(); 1547 } 1548 }; 1549 1550 private final IP2pInitiator mP2pInitiatorService = new IP2pInitiator.Stub() { 1551 1552 @Override 1553 public byte[] getGeneralBytes(int nativeHandle) throws RemoteException { 1554 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1555 1556 NativeP2pDevice device; 1557 1558 // Check if NFC is enabled 1559 if (!mIsNfcEnabled) { 1560 return null; 1561 } 1562 1563 /* find the device in the hmap */ 1564 device = (NativeP2pDevice) findObject(nativeHandle); 1565 if (device != null) { 1566 byte[] buff = device.getGeneralBytes(); 1567 if (buff == null) 1568 return null; 1569 return buff; 1570 } 1571 return null; 1572 } 1573 1574 @Override 1575 public int getMode(int nativeHandle) throws RemoteException { 1576 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1577 1578 NativeP2pDevice device; 1579 1580 // Check if NFC is enabled 1581 if (!mIsNfcEnabled) { 1582 return ErrorCodes.ERROR_NOT_INITIALIZED; 1583 } 1584 1585 /* find the device in the hmap */ 1586 device = (NativeP2pDevice) findObject(nativeHandle); 1587 if (device != null) { 1588 return device.getMode(); 1589 } 1590 return ErrorCodes.ERROR_INVALID_PARAM; 1591 } 1592 1593 @Override 1594 public byte[] receive(int nativeHandle) throws RemoteException { 1595 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1596 1597 NativeP2pDevice device; 1598 1599 // Check if NFC is enabled 1600 if (!mIsNfcEnabled) { 1601 return null; 1602 } 1603 1604 /* find the device in the hmap */ 1605 device = (NativeP2pDevice) findObject(nativeHandle); 1606 if (device != null) { 1607 byte[] buff = device.doReceive(); 1608 if (buff == null) 1609 return null; 1610 return buff; 1611 } 1612 /* Restart polling loop for notification */ 1613 applyRouting(); 1614 return null; 1615 } 1616 1617 @Override 1618 public boolean send(int nativeHandle, byte[] data) throws RemoteException { 1619 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1620 1621 NativeP2pDevice device; 1622 boolean isSuccess = false; 1623 1624 // Check if NFC is enabled 1625 if (!mIsNfcEnabled) { 1626 return isSuccess; 1627 } 1628 1629 /* find the device in the hmap */ 1630 device = (NativeP2pDevice) findObject(nativeHandle); 1631 if (device != null) { 1632 isSuccess = device.doSend(data); 1633 } 1634 return isSuccess; 1635 } 1636 }; 1637 1638 private final IP2pTarget mP2pTargetService = new IP2pTarget.Stub() { 1639 1640 @Override 1641 public int connect(int nativeHandle) throws RemoteException { 1642 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1643 1644 NativeP2pDevice device; 1645 1646 // Check if NFC is enabled 1647 if (!mIsNfcEnabled) { 1648 return ErrorCodes.ERROR_NOT_INITIALIZED; 1649 } 1650 1651 /* find the device in the hmap */ 1652 device = (NativeP2pDevice) findObject(nativeHandle); 1653 if (device != null) { 1654 if (device.doConnect()) { 1655 return ErrorCodes.SUCCESS; 1656 } 1657 } 1658 return ErrorCodes.ERROR_CONNECT; 1659 } 1660 1661 @Override 1662 public boolean disconnect(int nativeHandle) throws RemoteException { 1663 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1664 1665 NativeP2pDevice device; 1666 boolean isSuccess = false; 1667 1668 // Check if NFC is enabled 1669 if (!mIsNfcEnabled) { 1670 return isSuccess; 1671 } 1672 1673 /* find the device in the hmap */ 1674 device = (NativeP2pDevice) findObject(nativeHandle); 1675 if (device != null) { 1676 if (isSuccess = device.doDisconnect()) { 1677 /* remove the device from the hmap */ 1678 unregisterObject(nativeHandle); 1679 /* Restart polling loop for notification */ 1680 applyRouting(); 1681 } 1682 } 1683 return isSuccess; 1684 1685 } 1686 1687 @Override 1688 public byte[] getGeneralBytes(int nativeHandle) throws RemoteException { 1689 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1690 1691 NativeP2pDevice device; 1692 1693 // Check if NFC is enabled 1694 if (!mIsNfcEnabled) { 1695 return null; 1696 } 1697 1698 /* find the device in the hmap */ 1699 device = (NativeP2pDevice) findObject(nativeHandle); 1700 if (device != null) { 1701 byte[] buff = device.getGeneralBytes(); 1702 if (buff == null) 1703 return null; 1704 return buff; 1705 } 1706 return null; 1707 } 1708 1709 @Override 1710 public int getMode(int nativeHandle) throws RemoteException { 1711 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1712 1713 NativeP2pDevice device; 1714 1715 // Check if NFC is enabled 1716 if (!mIsNfcEnabled) { 1717 return ErrorCodes.ERROR_NOT_INITIALIZED; 1718 } 1719 1720 /* find the device in the hmap */ 1721 device = (NativeP2pDevice) findObject(nativeHandle); 1722 if (device != null) { 1723 return device.getMode(); 1724 } 1725 return ErrorCodes.ERROR_INVALID_PARAM; 1726 } 1727 1728 @Override 1729 public byte[] transceive(int nativeHandle, byte[] data) 1730 throws RemoteException { 1731 mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR); 1732 1733 NativeP2pDevice device; 1734 1735 // Check if NFC is enabled 1736 if (!mIsNfcEnabled) { 1737 return null; 1738 } 1739 1740 /* find the device in the hmap */ 1741 device = (NativeP2pDevice) findObject(nativeHandle); 1742 if (device != null) { 1743 byte[] buff = device.doTransceive(data); 1744 if (buff == null) 1745 return null; 1746 return buff; 1747 } 1748 return null; 1749 } 1750 }; 1751 1752 private void _nfcEeClose(boolean checkPid, int callingPid) throws IOException { 1753 // Blocks until a pending open() or transceive() times out. 1754 //TODO: This is incorrect behavior - the close should interrupt pending 1755 // operations. However this is not supported by current hardware. 1756 1757 synchronized(NfcService.this) { 1758 if (!mIsNfcEnabled) { 1759 throw new IOException("NFC adapter is disabled"); 1760 } 1761 if (mOpenEe == null) { 1762 throw new IOException("NFC EE closed"); 1763 } 1764 if (checkPid && mOpenEe.pid != -1 && callingPid != mOpenEe.pid) { 1765 throw new SecurityException("Wrong PID"); 1766 } 1767 1768 mManager.doResetIsoDepTimeout(); 1769 mSecureElement.doDisconnect(mOpenEe.handle); 1770 mOpenEe = null; 1771 1772 applyRouting(); 1773 } 1774 } 1775 1776 private INfcAdapterExtras mExtrasService = new INfcAdapterExtras.Stub() { 1777 private Bundle writeNoException() { 1778 Bundle p = new Bundle(); 1779 p.putInt("e", 0); 1780 return p; 1781 } 1782 private Bundle writeIoException(IOException e) { 1783 Bundle p = new Bundle(); 1784 p.putInt("e", -1); 1785 p.putString("m", e.getMessage()); 1786 return p; 1787 } 1788 1789 @Override 1790 public Bundle open(IBinder b) throws RemoteException { 1791 NfcService.enforceNfceeAdminPerm(mContext); 1792 1793 Bundle result; 1794 try { 1795 _open(b); 1796 result = writeNoException(); 1797 } catch (IOException e) { 1798 result = writeIoException(e); 1799 } 1800 return result; 1801 } 1802 1803 private void _open(IBinder b) throws IOException, RemoteException { 1804 synchronized(NfcService.this) { 1805 if (!mIsNfcEnabled) { 1806 throw new IOException("NFC adapter is disabled"); 1807 } 1808 if (mOpenEe != null) { 1809 throw new IOException("NFC EE already open"); 1810 } 1811 1812 int handle = mSecureElement.doOpenSecureElementConnection(); 1813 if (handle == 0) { 1814 throw new IOException("NFC EE failed to open"); 1815 } 1816 mManager.doSetIsoDepTimeout(10000); 1817 1818 mOpenEe = new OpenSecureElement(getCallingPid(), handle); 1819 try { 1820 b.linkToDeath(mOpenEe, 0); 1821 } catch (RemoteException e) { 1822 mOpenEe.binderDied(); 1823 } 1824 } 1825 } 1826 1827 @Override 1828 public Bundle close() throws RemoteException { 1829 NfcService.enforceNfceeAdminPerm(mContext); 1830 1831 Bundle result; 1832 try { 1833 _nfcEeClose(true, getCallingPid()); 1834 result = writeNoException(); 1835 } catch (IOException e) { 1836 result = writeIoException(e); 1837 } 1838 return result; 1839 } 1840 1841 @Override 1842 public Bundle transceive(byte[] in) throws RemoteException { 1843 NfcService.enforceNfceeAdminPerm(mContext); 1844 1845 Bundle result; 1846 byte[] out; 1847 try { 1848 out = _transceive(in); 1849 result = writeNoException(); 1850 result.putByteArray("out", out); 1851 } catch (IOException e) { 1852 result = writeIoException(e); 1853 } 1854 return result; 1855 } 1856 1857 private byte[] _transceive(byte[] data) throws IOException, RemoteException { 1858 synchronized(NfcService.this) { 1859 if (!mIsNfcEnabled) { 1860 throw new IOException("NFC is not enabled"); 1861 } 1862 if (mOpenEe == null){ 1863 throw new IOException("NFC EE is not open"); 1864 } 1865 if (getCallingPid() != mOpenEe.pid) { 1866 throw new SecurityException("Wrong PID"); 1867 } 1868 } 1869 1870 return mSecureElement.doTransceive(mOpenEe.handle, data); 1871 } 1872 1873 @Override 1874 public int getCardEmulationRoute() throws RemoteException { 1875 NfcService.enforceNfceeAdminPerm(mContext); 1876 return mEeRoutingState; 1877 } 1878 1879 @Override 1880 public void setCardEmulationRoute(int route) throws RemoteException { 1881 NfcService.enforceNfceeAdminPerm(mContext); 1882 mEeRoutingState = route; 1883 applyRouting(); 1884 } 1885 1886 @Override 1887 public void registerTearDownApdus(String packageName, ApduList apdu) throws RemoteException { 1888 NfcService.enforceNfceeAdminPerm(mContext); 1889 Log.w(TAG, "NOP"); 1890 //TODO: Remove this API 1891 } 1892 1893 @Override 1894 public void unregisterTearDownApdus(String packageName) throws RemoteException { 1895 NfcService.enforceNfceeAdminPerm(mContext); 1896 Log.w(TAG, "NOP"); 1897 //TODO: Remove this API 1898 } 1899 }; 1900 1901 /** resources kept while secure element is open */ 1902 private class OpenSecureElement implements IBinder.DeathRecipient { 1903 public int pid; // pid that opened SE 1904 public int handle; // low-level handle 1905 public OpenSecureElement(int pid, int handle) { 1906 this.pid = pid; 1907 this.handle = handle; 1908 } 1909 @Override 1910 public void binderDied() { 1911 synchronized (NfcService.this) { 1912 if (DBG) Log.d(TAG, "Tracked app " + pid + " died"); 1913 pid = -1; 1914 try { 1915 _nfcEeClose(false, -1); 1916 } catch (IOException e) { /* already closed */ } 1917 } 1918 } 1919 } 1920 1921 private boolean _enable(boolean oldEnabledState) { 1922 applyProperties(); 1923 1924 boolean isSuccess = mManager.initialize(); 1925 if (isSuccess) { 1926 mIsNfcEnabled = true; 1927 mIsDiscoveryOn = true; 1928 1929 /* Start polling loop */ 1930 applyRouting(); 1931 1932 /* bring up the my tag server */ 1933 mNdefPushServer.start(); 1934 1935 } else { 1936 Log.w(TAG, "Error enabling NFC"); 1937 mIsNfcEnabled = false; 1938 } 1939 1940 updateNfcOnSetting(oldEnabledState); 1941 1942 return isSuccess; 1943 } 1944 1945 private boolean _disable(boolean oldEnabledState) { 1946 /* sometimes mManager.deinitialize() hangs, watch-dog it */ 1947 WatchDogThread watchDog = new WatchDogThread(); 1948 watchDog.start(); 1949 1950 boolean isSuccess; 1951 1952 /* tear down the my tag server */ 1953 mNdefPushServer.stop(); 1954 1955 // Stop watchdog if tag present 1956 // A convenient way to stop the watchdog properly consists of 1957 // disconnecting the tag. The polling loop shall be stopped before 1958 // to avoid the tag being discovered again. 1959 mIsDiscoveryOn = false; 1960 applyRouting(); 1961 maybeDisconnectTarget(); 1962 1963 isSuccess = mManager.deinitialize(); 1964 if (DBG) Log.d(TAG, "NFC success of deinitialize = " + isSuccess); 1965 if (isSuccess) { 1966 mIsNfcEnabled = false; 1967 // Clear out any old dispatch overrides and NDEF push message 1968 synchronized (this) { 1969 mDispatchOverrideFilters = null; 1970 mDispatchOverrideIntent = null; 1971 } 1972 mNdefPushClient.setForegroundMessage(null); 1973 } 1974 1975 updateNfcOnSetting(oldEnabledState); 1976 1977 watchDog.cancel(); 1978 return isSuccess; 1979 } 1980 1981 private class WatchDogThread extends Thread { 1982 boolean mWatchDogCanceled = false; 1983 @Override 1984 public void run() { 1985 boolean slept = false; 1986 while (!slept) { 1987 try { 1988 Thread.sleep(10000); 1989 slept = true; 1990 } catch (InterruptedException e) { } 1991 } 1992 synchronized (this) { 1993 if (!mWatchDogCanceled) { 1994 // Trigger watch-dog 1995 Log.e(TAG, "Watch dog triggered"); 1996 mManager.doAbort(); 1997 } 1998 } 1999 } 2000 public synchronized void cancel() { 2001 mWatchDogCanceled = true; 2002 } 2003 } 2004 2005 /** apply NFC discovery and EE routing */ 2006 private synchronized void applyRouting() { 2007 if (mIsNfcEnabled && mOpenEe == null) { 2008 if (mScreenOn) { 2009 if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) { 2010 Log.d(TAG, "NFC-EE routing ON"); 2011 mManager.doSelectSecureElement(SECURE_ELEMENT_ID); 2012 } else { 2013 Log.d(TAG, "NFC-EE routing OFF"); 2014 mManager.doDeselectSecureElement(SECURE_ELEMENT_ID); 2015 } 2016 if (mIsDiscoveryOn) { 2017 Log.d(TAG, "NFC-C discovery ON"); 2018 mManager.enableDiscovery(DISCOVERY_MODE_READER); 2019 } else { 2020 Log.d(TAG, "NFC-C discovery OFF"); 2021 mManager.disableDiscovery(); 2022 } 2023 } else { 2024 Log.d(TAG, "NFC-EE routing OFF"); 2025 mManager.doDeselectSecureElement(SECURE_ELEMENT_ID); 2026 Log.d(TAG, "NFC-C discovery OFF"); 2027 mManager.disableDiscovery(); 2028 } 2029 } 2030 } 2031 2032 /** Disconnect any target if present */ 2033 private synchronized void maybeDisconnectTarget() { 2034 if (mIsNfcEnabled) { 2035 Iterator<?> iterator = mObjectMap.values().iterator(); 2036 while(iterator.hasNext()) { 2037 Object object = iterator.next(); 2038 if(object instanceof NativeNfcTag) { 2039 // Disconnect from tags 2040 NativeNfcTag tag = (NativeNfcTag) object; 2041 tag.disconnect(); 2042 } 2043 else if(object instanceof NativeP2pDevice) { 2044 // Disconnect from P2P devices 2045 NativeP2pDevice device = (NativeP2pDevice) object; 2046 if (device.getMode() == NativeP2pDevice.MODE_P2P_TARGET) { 2047 // Remote peer is target, request disconnection 2048 device.doDisconnect(); 2049 } 2050 else { 2051 // Remote peer is initiator, we cannot disconnect 2052 // Just wait for field removal 2053 } 2054 } 2055 iterator.remove(); 2056 } 2057 } 2058 } 2059 2060 //TODO: dont hardcode this 2061 private static final byte[][] SE_RESET_APDUS = { 2062 {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, 2063 {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00}, 2064 {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00}, 2065 {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, 2066 {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00}, 2067 {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00}, 2068 {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00}, 2069 }; 2070 2071 private void resetSeOnFirstBoot() { 2072 if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) { 2073 Log.i(TAG, "First Boot"); 2074 mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false); 2075 mPrefsEditor.apply(); 2076 executeSeReset(); 2077 } 2078 } 2079 2080 private synchronized void executeSeReset() { 2081 // TODO: read SE reset list from /system/etc 2082 //List<byte[]> apdus = readSeResetApdus(); 2083 byte[][]apdus = SE_RESET_APDUS; 2084 if (apdus == null) { 2085 return; 2086 } 2087 2088 boolean tempEnable = !mIsNfcEnabled; 2089 if (tempEnable) { 2090 if (!_enable(false)) { 2091 Log.w(TAG, "Could not enable NFC to reset EE!"); 2092 return; 2093 } 2094 } 2095 2096 Log.i(TAG, "Executing SE Reset Script"); 2097 int handle = mSecureElement.doOpenSecureElementConnection(); 2098 if (handle == 0) { 2099 Log.e(TAG, "Could not open the secure element!"); 2100 if (tempEnable) { 2101 _disable(true); 2102 } 2103 return; 2104 } 2105 2106 mManager.doSetIsoDepTimeout(10000); 2107 2108 for (byte[] cmd : apdus) { 2109 mSecureElement.doTransceive(handle, cmd); 2110 } 2111 2112 mManager.doResetIsoDepTimeout(); 2113 2114 mSecureElement.doDisconnect(handle); 2115 2116 if (tempEnable) { 2117 _disable(true); 2118 } 2119 } 2120 2121 private List<byte[]> readSeResetApdus() { 2122 FileInputStream input = null; 2123 List<byte[]> apdus = null; 2124 2125 try { 2126 input = openFileInput(SE_RESET_SCRIPT_FILE_NAME); 2127 DataInputStream stream = new DataInputStream(input); 2128 2129 int commandsSize = stream.readInt(); 2130 apdus = new ArrayList<byte[]>(commandsSize); 2131 2132 for (int i = 0 ; i < commandsSize ; i++) { 2133 int length = stream.readInt(); 2134 2135 byte[] cmd = new byte[length]; 2136 2137 stream.read(cmd); 2138 apdus.add(cmd); 2139 } 2140 2141 return apdus; 2142 } catch (FileNotFoundException e) { 2143 Log.e(TAG, "SE Reset Script not found: " + SE_RESET_SCRIPT_FILE_NAME); 2144 } catch (IOException e) { 2145 Log.e(TAG, "SE Reset Script corrupt: ", e); 2146 apdus = null; 2147 } finally { 2148 try { 2149 if (input != null) { 2150 input.close(); 2151 } 2152 } catch (IOException e) { 2153 // Ignore 2154 } 2155 } 2156 return apdus; 2157 } 2158 2159 private void applyProperties() { 2160 mManager.doSetProperties(PROPERTY_LLCP_LTO, mPrefs.getInt(PREF_LLCP_LTO, LLCP_LTO_DEFAULT)); 2161 mManager.doSetProperties(PROPERTY_LLCP_MIU, mPrefs.getInt(PREF_LLCP_MIU, LLCP_MIU_DEFAULT)); 2162 mManager.doSetProperties(PROPERTY_LLCP_WKS, mPrefs.getInt(PREF_LLCP_WKS, LLCP_WKS_DEFAULT)); 2163 mManager.doSetProperties(PROPERTY_LLCP_OPT, mPrefs.getInt(PREF_LLCP_OPT, LLCP_OPT_DEFAULT)); 2164 mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_A, 2165 mPrefs.getBoolean(PREF_DISCOVERY_A, DISCOVERY_A_DEFAULT) ? 1 : 0); 2166 mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_B, 2167 mPrefs.getBoolean(PREF_DISCOVERY_B, DISCOVERY_B_DEFAULT) ? 1 : 0); 2168 mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_F, 2169 mPrefs.getBoolean(PREF_DISCOVERY_F, DISCOVERY_F_DEFAULT) ? 1 : 0); 2170 mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_15693, 2171 mPrefs.getBoolean(PREF_DISCOVERY_15693, DISCOVERY_15693_DEFAULT) ? 1 : 0); 2172 mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_NFCIP, 2173 mPrefs.getBoolean(PREF_DISCOVERY_NFCIP, DISCOVERY_NFCIP_DEFAULT) ? 1 : 0); 2174 } 2175 2176 private void updateNfcOnSetting(boolean oldEnabledState) { 2177 mPrefsEditor.putBoolean(PREF_NFC_ON, mIsNfcEnabled); 2178 mPrefsEditor.apply(); 2179 2180 synchronized(this) { 2181 if (oldEnabledState != mIsNfcEnabled) { 2182 Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGE); 2183 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2184 intent.putExtra(NfcAdapter.EXTRA_NEW_BOOLEAN_STATE, mIsNfcEnabled); 2185 mContext.sendBroadcast(intent); 2186 } 2187 2188 if (mIsNfcEnabled) { 2189 2190 Context context = getApplicationContext(); 2191 2192 // Set this to null by default. If there isn't a tag on disk 2193 // or if there was an error reading the tag then this will cause 2194 // the status bar icon to be removed. 2195 NdefMessage myTag = null; 2196 2197 FileInputStream input = null; 2198 2199 try { 2200 input = context.openFileInput(MY_TAG_FILE_NAME); 2201 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 2202 2203 byte[] buffer = new byte[4096]; 2204 int read = 0; 2205 while ((read = input.read(buffer)) > 0) { 2206 bytes.write(buffer, 0, read); 2207 } 2208 2209 myTag = new NdefMessage(bytes.toByteArray()); 2210 } catch (FileNotFoundException e) { 2211 // Ignore. 2212 } catch (IOException e) { 2213 Log.e(TAG, "Could not read mytag file: ", e); 2214 context.deleteFile(MY_TAG_FILE_NAME); 2215 } catch (FormatException e) { 2216 Log.e(TAG, "Invalid NdefMessage for mytag", e); 2217 context.deleteFile(MY_TAG_FILE_NAME); 2218 } finally { 2219 try { 2220 if (input != null) { 2221 input.close(); 2222 } 2223 } catch (IOException e) { 2224 // Ignore 2225 } 2226 } 2227 2228 try { 2229 mNfcAdapter.localSet(myTag); 2230 } catch (RemoteException e) { 2231 // Ignore 2232 } 2233 } else { 2234 sendMessage(MSG_HIDE_MY_TAG_ICON, null); 2235 } 2236 } 2237 } 2238 2239 // Reset all internals 2240 private synchronized void reset() { 2241 // TODO: none of these appear to be synchronized but are 2242 // read/written from different threads (notably Binder threads)... 2243 2244 // Clear tables 2245 mObjectMap.clear(); 2246 mSocketMap.clear(); 2247 2248 // Reset variables 2249 mIsNfcEnabled = false; 2250 } 2251 2252 private synchronized Object findObject(int key) { 2253 Object device = null; 2254 2255 device = mObjectMap.get(key); 2256 if (device == null) { 2257 Log.w(TAG, "Handle not found !"); 2258 } 2259 2260 return device; 2261 } 2262 2263 synchronized void registerTagObject(NativeNfcTag nativeTag) { 2264 mObjectMap.put(nativeTag.getHandle(), nativeTag); 2265 } 2266 2267 synchronized void unregisterObject(int handle) { 2268 mObjectMap.remove(handle); 2269 } 2270 2271 private synchronized Object findSocket(int key) { 2272 if (mSocketMap == null) { 2273 return null; 2274 } 2275 return mSocketMap.get(key); 2276 } 2277 2278 private void RemoveSocket(int key) { 2279 mSocketMap.remove(key); 2280 } 2281 2282 /** For use by code in this process */ 2283 public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength) { 2284 try { 2285 int handle = mNfcAdapter.createLlcpSocket(sap, miu, rw, linearBufferLength); 2286 if (ErrorCodes.isError(handle)) { 2287 Log.e(TAG, "unable to create socket: " + ErrorCodes.asString(handle)); 2288 return null; 2289 } 2290 return new LlcpSocket(mLlcpSocket, handle); 2291 } catch (RemoteException e) { 2292 // This will never happen since the code is calling into it's own process 2293 throw new IllegalStateException("unable to talk to myself", e); 2294 } 2295 } 2296 2297 /** For use by code in this process */ 2298 public LlcpServiceSocket createLlcpServiceSocket(int sap, String sn, int miu, int rw, 2299 int linearBufferLength) { 2300 try { 2301 int handle = mNfcAdapter.createLlcpServiceSocket(sap, sn, miu, rw, linearBufferLength); 2302 if (ErrorCodes.isError(handle)) { 2303 Log.e(TAG, "unable to create socket: " + ErrorCodes.asString(handle)); 2304 return null; 2305 } 2306 return new LlcpServiceSocket(mLlcpServerSocketService, mLlcpSocket, handle); 2307 } catch (RemoteException e) { 2308 // This will never happen since the code is calling into it's own process 2309 throw new IllegalStateException("unable to talk to myself", e); 2310 } 2311 } 2312 2313 private void activateLlcpLink() { 2314 /* Broadcast Intent Link LLCP activated */ 2315 Intent LlcpLinkIntent = new Intent(); 2316 LlcpLinkIntent.setAction(NfcAdapter.ACTION_LLCP_LINK_STATE_CHANGED); 2317 2318 LlcpLinkIntent.putExtra(NfcAdapter.EXTRA_LLCP_LINK_STATE_CHANGED, 2319 NfcAdapter.LLCP_LINK_STATE_ACTIVATED); 2320 2321 if (DBG) Log.d(TAG, "Broadcasting LLCP activation"); 2322 mContext.sendOrderedBroadcast(LlcpLinkIntent, NFC_PERM); 2323 } 2324 2325 public void sendMockNdefTag(NdefMessage msg) { 2326 sendMessage(MSG_MOCK_NDEF, msg); 2327 } 2328 2329 void sendMessage(int what, Object obj) { 2330 Message msg = mHandler.obtainMessage(); 2331 msg.what = what; 2332 msg.obj = obj; 2333 mHandler.sendMessage(msg); 2334 } 2335 2336 final class NfcServiceHandler extends Handler { 2337 2338 public NdefMessage[] findAndReadNdef(NativeNfcTag nativeTag) { 2339 // Try to find NDEF on any of the technologies. 2340 int[] technologies = nativeTag.getTechList(); 2341 int[] handles = nativeTag.getHandleList(); 2342 int techIndex = 0; 2343 int lastHandleScanned = 0; 2344 boolean ndefFoundAndConnected = false; 2345 NdefMessage[] ndefMsgs = null; 2346 boolean foundFormattable = false; 2347 int formattableHandle = 0; 2348 int formattableTechnology = 0; 2349 2350 while ((!ndefFoundAndConnected) && (techIndex < technologies.length)) { 2351 if (handles[techIndex] != lastHandleScanned) { 2352 // We haven't seen this handle yet, connect and checkndef 2353 if (nativeTag.connect(technologies[techIndex])) { 2354 // Check if this type is NDEF formatable 2355 if (!foundFormattable) { 2356 if (nativeTag.isNdefFormatable()) { 2357 foundFormattable = true; 2358 formattableHandle = nativeTag.getConnectedHandle(); 2359 formattableTechnology = nativeTag.getConnectedTechnology(); 2360 // We'll only add formattable tech if no ndef is 2361 // found - this is because libNFC refuses to format 2362 // an already NDEF formatted tag. 2363 } 2364 nativeTag.reconnect(); 2365 } // else, already found formattable technology 2366 2367 int[] ndefinfo = new int[2]; 2368 if (nativeTag.checkNdef(ndefinfo)) { 2369 ndefFoundAndConnected = true; 2370 boolean generateEmptyNdef = false; 2371 2372 int supportedNdefLength = ndefinfo[0]; 2373 int cardState = ndefinfo[1]; 2374 byte[] buff = nativeTag.read(); 2375 if (buff != null) { 2376 ndefMsgs = new NdefMessage[1]; 2377 try { 2378 ndefMsgs[0] = new NdefMessage(buff); 2379 nativeTag.addNdefTechnology(ndefMsgs[0], 2380 nativeTag.getConnectedHandle(), 2381 nativeTag.getConnectedLibNfcType(), 2382 nativeTag.getConnectedTechnology(), 2383 supportedNdefLength, cardState); 2384 nativeTag.reconnect(); 2385 } catch (FormatException e) { 2386 // Create an intent anyway, without NDEF messages 2387 generateEmptyNdef = true; 2388 } 2389 } else { 2390 generateEmptyNdef = true; 2391 } 2392 2393 if (generateEmptyNdef) { 2394 ndefMsgs = new NdefMessage[] { }; 2395 nativeTag.addNdefTechnology(null, 2396 nativeTag.getConnectedHandle(), 2397 nativeTag.getConnectedLibNfcType(), 2398 nativeTag.getConnectedTechnology(), 2399 supportedNdefLength, cardState); 2400 nativeTag.reconnect(); 2401 } 2402 } // else, no NDEF on this tech, continue loop 2403 } else { 2404 // Connect failed, tag maybe lost. Try next handle 2405 // anyway. 2406 } 2407 } 2408 lastHandleScanned = handles[techIndex]; 2409 techIndex++; 2410 } 2411 if (ndefMsgs == null && foundFormattable) { 2412 // Tag is not NDEF yet, and found a formattable target, 2413 // so add formattable tech to tech list. 2414 nativeTag.addNdefFormatableTechnology( 2415 formattableHandle, 2416 formattableTechnology); 2417 } 2418 2419 return ndefMsgs; 2420 } 2421 2422 @Override 2423 public void handleMessage(Message msg) { 2424 switch (msg.what) { 2425 case MSG_MOCK_NDEF: { 2426 NdefMessage ndefMsg = (NdefMessage) msg.obj; 2427 Tag tag = Tag.createMockTag(new byte[] { 0x00 }, 2428 new int[] { }, 2429 new Bundle[] { }); 2430 Log.d(TAG, "mock NDEF tag, starting corresponding activity"); 2431 Log.d(TAG, tag.toString()); 2432 dispatchTag(tag, new NdefMessage[] { ndefMsg }); 2433 break; 2434 } 2435 2436 case MSG_NDEF_TAG: 2437 if (DBG) Log.d(TAG, "Tag detected, notifying applications"); 2438 NativeNfcTag nativeTag = (NativeNfcTag) msg.obj; 2439 NdefMessage[] ndefMsgs = findAndReadNdef(nativeTag); 2440 2441 if (ndefMsgs != null) { 2442 nativeTag.startPresenceChecking(); 2443 dispatchNativeTag(nativeTag, ndefMsgs); 2444 } else { 2445 // No ndef found or connect failed, just try to reconnect and dispatch 2446 if (nativeTag.reconnect()) { 2447 nativeTag.startPresenceChecking(); 2448 dispatchNativeTag(nativeTag, null); 2449 } else { 2450 Log.w(TAG, "Failed to connect to tag"); 2451 nativeTag.disconnect(); 2452 } 2453 } 2454 break; 2455 2456 case MSG_CARD_EMULATION: 2457 if (DBG) Log.d(TAG, "Card Emulation message"); 2458 byte[] aid = (byte[]) msg.obj; 2459 /* Send broadcast */ 2460 Intent aidIntent = new Intent(); 2461 aidIntent.setAction(ACTION_AID_SELECTED); 2462 aidIntent.putExtra(EXTRA_AID, aid); 2463 if (DBG) Log.d(TAG, "Broadcasting ACTION_AID_SELECTED"); 2464 mContext.sendBroadcast(aidIntent, NFCEE_ADMIN_PERM); 2465 break; 2466 2467 case MSG_LLCP_LINK_ACTIVATION: 2468 NativeP2pDevice device = (NativeP2pDevice) msg.obj; 2469 2470 Log.d(TAG, "LLCP Activation message"); 2471 2472 if (device.getMode() == NativeP2pDevice.MODE_P2P_TARGET) { 2473 if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET"); 2474 if (device.doConnect()) { 2475 /* Check Llcp compliancy */ 2476 if (mManager.doCheckLlcp()) { 2477 /* Activate Llcp Link */ 2478 if (mManager.doActivateLlcp()) { 2479 if (DBG) Log.d(TAG, "Initiator Activate LLCP OK"); 2480 // Register P2P device 2481 mObjectMap.put(device.getHandle(), device); 2482 activateLlcpLink(); 2483 } else { 2484 /* should not happen */ 2485 Log.w(TAG, "Initiator Activate LLCP NOK. Disconnect."); 2486 device.doDisconnect(); 2487 } 2488 2489 } else { 2490 if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect."); 2491 device.doDisconnect(); 2492 } 2493 } else { 2494 if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted..."); 2495 /* The polling loop should have been restarted in failing doConnect */ 2496 } 2497 2498 } else if (device.getMode() == NativeP2pDevice.MODE_P2P_INITIATOR) { 2499 if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR"); 2500 /* Check Llcp compliancy */ 2501 if (mManager.doCheckLlcp()) { 2502 /* Activate Llcp Link */ 2503 if (mManager.doActivateLlcp()) { 2504 if (DBG) Log.d(TAG, "Target Activate LLCP OK"); 2505 // Register P2P device 2506 mObjectMap.put(device.getHandle(), device); 2507 activateLlcpLink(); 2508 } 2509 } else { 2510 Log.w(TAG, "checkLlcp failed"); 2511 } 2512 } 2513 break; 2514 2515 case MSG_LLCP_LINK_DEACTIVATED: 2516 device = (NativeP2pDevice) msg.obj; 2517 2518 Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop."); 2519 synchronized (NfcService.this) { 2520 /* Check if the device has been already unregistered */ 2521 if (mObjectMap.remove(device.getHandle()) != null) { 2522 /* Disconnect if we are initiator */ 2523 if (device.getMode() == NativeP2pDevice.MODE_P2P_TARGET) { 2524 if (DBG) Log.d(TAG, "disconnecting from target"); 2525 /* Restart polling loop */ 2526 device.doDisconnect(); 2527 } else { 2528 if (DBG) Log.d(TAG, "not disconnecting from initiator"); 2529 } 2530 } 2531 } 2532 2533 /* Broadcast Intent Link LLCP activated */ 2534 Intent LlcpLinkIntent = new Intent(); 2535 LlcpLinkIntent.setAction(NfcAdapter.ACTION_LLCP_LINK_STATE_CHANGED); 2536 LlcpLinkIntent.putExtra(NfcAdapter.EXTRA_LLCP_LINK_STATE_CHANGED, 2537 NfcAdapter.LLCP_LINK_STATE_DEACTIVATED); 2538 if (DBG) Log.d(TAG, "Broadcasting LLCP deactivation"); 2539 mContext.sendOrderedBroadcast(LlcpLinkIntent, NFC_PERM); 2540 break; 2541 2542 case MSG_TARGET_DESELECTED: 2543 /* Broadcast Intent Target Deselected */ 2544 if (DBG) Log.d(TAG, "Target Deselected"); 2545 Intent TargetDeselectedIntent = new Intent(); 2546 TargetDeselectedIntent.setAction(mManager.INTERNAL_TARGET_DESELECTED_ACTION); 2547 if (DBG) Log.d(TAG, "Broadcasting Intent"); 2548 mContext.sendOrderedBroadcast(TargetDeselectedIntent, NFC_PERM); 2549 break; 2550 2551 case MSG_SHOW_MY_TAG_ICON: { 2552 StatusBarManager sb = (StatusBarManager) getSystemService( 2553 Context.STATUS_BAR_SERVICE); 2554 sb.setIcon("nfc", R.drawable.stat_sys_nfc, 0); 2555 break; 2556 } 2557 2558 case MSG_HIDE_MY_TAG_ICON: { 2559 StatusBarManager sb = (StatusBarManager) getSystemService( 2560 Context.STATUS_BAR_SERVICE); 2561 sb.removeIcon("nfc"); 2562 break; 2563 } 2564 2565 case MSG_SE_FIELD_ACTIVATED:{ 2566 if (DBG) Log.d(TAG, "SE FIELD ACTIVATED"); 2567 Intent eventFieldOnIntent = new Intent(); 2568 eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED); 2569 if (DBG) Log.d(TAG, "Broadcasting Intent"); 2570 mContext.sendBroadcast(eventFieldOnIntent, NFCEE_ADMIN_PERM); 2571 break; 2572 } 2573 2574 case MSG_SE_FIELD_DEACTIVATED:{ 2575 if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED"); 2576 Intent eventFieldOffIntent = new Intent(); 2577 eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED); 2578 if (DBG) Log.d(TAG, "Broadcasting Intent"); 2579 mContext.sendBroadcast(eventFieldOffIntent, NFCEE_ADMIN_PERM); 2580 break; 2581 } 2582 2583 default: 2584 Log.e(TAG, "Unknown message received"); 2585 break; 2586 } 2587 } 2588 2589 private Intent buildTagIntent(Tag tag, NdefMessage[] msgs, String action) { 2590 Intent intent = new Intent(action); 2591 intent.putExtra(NfcAdapter.EXTRA_TAG, tag); 2592 intent.putExtra(NfcAdapter.EXTRA_ID, tag.getId()); 2593 intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, msgs); 2594 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2595 return intent; 2596 } 2597 2598 private void dispatchNativeTag(NativeNfcTag nativeTag, NdefMessage[] msgs) { 2599 Tag tag = new Tag(nativeTag.getUid(), nativeTag.getTechList(), 2600 nativeTag.getTechExtras(), nativeTag.getHandle(), mNfcTagService); 2601 registerTagObject(nativeTag); 2602 if (!dispatchTag(tag, msgs)) { 2603 unregisterObject(nativeTag.getHandle()); 2604 nativeTag.disconnect(); 2605 } 2606 } 2607 2608 public byte[] concat(byte[]... arrays) { 2609 int length = 0; 2610 for (byte[] array : arrays) { 2611 length += array.length; 2612 } 2613 byte[] result = new byte[length]; 2614 int pos = 0; 2615 for (byte[] array : arrays) { 2616 System.arraycopy(array, 0, result, pos, array.length); 2617 pos += array.length; 2618 } 2619 return result; 2620 } 2621 2622 private Uri parseWellKnownUriRecord(NdefRecord record) { 2623 byte[] payload = record.getPayload(); 2624 2625 /* 2626 * payload[0] contains the URI Identifier Code, per the 2627 * NFC Forum "URI Record Type Definition" section 3.2.2. 2628 * 2629 * payload[1]...payload[payload.length - 1] contains the rest of 2630 * the URI. 2631 */ 2632 String prefix = URI_PREFIX_MAP[(payload[0] & 0xff)]; 2633 byte[] fullUri = concat(prefix.getBytes(Charsets.UTF_8), 2634 Arrays.copyOfRange(payload, 1, payload.length)); 2635 return Uri.parse(new String(fullUri, Charsets.UTF_8)); 2636 } 2637 2638 private boolean setTypeOrDataFromNdef(Intent intent, NdefRecord record) { 2639 short tnf = record.getTnf(); 2640 byte[] type = record.getType(); 2641 try { 2642 switch (tnf) { 2643 case NdefRecord.TNF_MIME_MEDIA: { 2644 intent.setType(new String(type, Charsets.US_ASCII)); 2645 return true; 2646 } 2647 2648 case NdefRecord.TNF_ABSOLUTE_URI: { 2649 intent.setData(Uri.parse(new String(type, Charsets.UTF_8))); 2650 return true; 2651 } 2652 2653 case NdefRecord.TNF_WELL_KNOWN: { 2654 byte[] payload = record.getPayload(); 2655 if (payload == null || payload.length == 0) return false; 2656 if (Arrays.equals(type, NdefRecord.RTD_TEXT)) { 2657 intent.setType("text/plain"); 2658 return true; 2659 } else if (Arrays.equals(type, NdefRecord.RTD_SMART_POSTER)) { 2660 // Parse the smart poster looking for the URI 2661 try { 2662 NdefMessage msg = new NdefMessage(record.getPayload()); 2663 for (NdefRecord subRecord : msg.getRecords()) { 2664 short subTnf = subRecord.getTnf(); 2665 if (subTnf == NdefRecord.TNF_WELL_KNOWN 2666 && Arrays.equals(subRecord.getType(), 2667 NdefRecord.RTD_URI)) { 2668 intent.setData(parseWellKnownUriRecord(subRecord)); 2669 return true; 2670 } else if (subTnf == NdefRecord.TNF_ABSOLUTE_URI) { 2671 intent.setData(Uri.parse(new String(subRecord.getType(), 2672 Charsets.UTF_8))); 2673 return true; 2674 } 2675 } 2676 } catch (FormatException e) { 2677 return false; 2678 } 2679 } else if (Arrays.equals(type, NdefRecord.RTD_URI)) { 2680 intent.setData(parseWellKnownUriRecord(record)); 2681 return true; 2682 } 2683 return false; 2684 } 2685 2686 case NdefRecord.TNF_EXTERNAL_TYPE: { 2687 intent.setData(Uri.parse("vnd.android.nfc://ext/" + 2688 new String(record.getType(), Charsets.US_ASCII))); 2689 return true; 2690 } 2691 } 2692 return false; 2693 } catch (Exception e) { 2694 Log.e(TAG, "failed to parse record", e); 2695 return false; 2696 } 2697 } 2698 2699 /** Returns false if no activities were found to dispatch to */ 2700 private boolean dispatchTag(Tag tag, NdefMessage[] msgs) { 2701 if (DBG) { 2702 Log.d(TAG, "Dispatching tag"); 2703 Log.d(TAG, tag.toString()); 2704 } 2705 2706 IntentFilter[] overrideFilters; 2707 PendingIntent overrideIntent; 2708 String[][] overrideTechLists; 2709 boolean foregroundNdefPush = mNdefPushClient.getForegroundMessage() != null; 2710 synchronized (mNfcAdapter) { 2711 overrideFilters = mDispatchOverrideFilters; 2712 overrideIntent = mDispatchOverrideIntent; 2713 overrideTechLists = mDispatchOverrideTechLists; 2714 } 2715 2716 // First look for dispatch overrides 2717 if (overrideIntent != null) { 2718 if (DBG) Log.d(TAG, "Attempting to dispatch tag with override"); 2719 try { 2720 if (dispatchTagInternal(tag, msgs, overrideIntent, overrideFilters, 2721 overrideTechLists)) { 2722 if (DBG) Log.d(TAG, "Dispatched to override"); 2723 return true; 2724 } 2725 Log.w(TAG, "Dispatch override registered, but no filters matched"); 2726 } catch (CanceledException e) { 2727 Log.w(TAG, "Dispatch overrides pending intent was canceled"); 2728 synchronized (mNfcAdapter) { 2729 mDispatchOverrideFilters = null; 2730 mDispatchOverrideIntent = null; 2731 mDispatchOverrideTechLists = null; 2732 } 2733 } 2734 } 2735 2736 // If there is not foreground NDEF push setup try a normal dispatch. 2737 // 2738 // This is avoided when disabled in the NDEF push case to avoid the situation where each 2739 // user has a different app in the foreground, causing each to launch itself on the 2740 // remote device and the apps swapping which is in the foreground on each phone. 2741 if (!foregroundNdefPush) { 2742 try { 2743 return dispatchTagInternal(tag, msgs, null, null, null); 2744 } catch (CanceledException e) { 2745 Log.e(TAG, "CanceledException unexpected here", e); 2746 return false; 2747 } 2748 } 2749 2750 return false; 2751 } 2752 2753 /** Returns true if the tech list filter matches the techs on the tag */ 2754 private boolean filterMatch(String[] tagTechs, String[] filterTechs) { 2755 if (filterTechs == null || filterTechs.length == 0) return false; 2756 2757 for (String tech : filterTechs) { 2758 if (Arrays.binarySearch(tagTechs, tech) < 0) { 2759 return false; 2760 } 2761 } 2762 return true; 2763 } 2764 2765 // Dispatch to either an override pending intent or a standard startActivity() 2766 private boolean dispatchTagInternal(Tag tag, NdefMessage[] msgs, 2767 PendingIntent overrideIntent, IntentFilter[] overrideFilters, 2768 String[][] overrideTechLists) 2769 throws CanceledException{ 2770 Intent intent; 2771 2772 // 2773 // Try the NDEF content specific dispatch 2774 // 2775 if (msgs != null && msgs.length > 0) { 2776 NdefMessage msg = msgs[0]; 2777 NdefRecord[] records = msg.getRecords(); 2778 if (records.length > 0) { 2779 // Found valid NDEF data, try to dispatch that first 2780 NdefRecord record = records[0]; 2781 2782 intent = buildTagIntent(tag, msgs, NfcAdapter.ACTION_NDEF_DISCOVERED); 2783 if (setTypeOrDataFromNdef(intent, record)) { 2784 // The record contains filterable data, try to start a matching activity 2785 if (startDispatchActivity(intent, overrideIntent, overrideFilters, 2786 overrideTechLists)) { 2787 // If an activity is found then skip further dispatching 2788 return true; 2789 } else { 2790 if (DBG) Log.d(TAG, "No activities for NDEF handling of " + intent); 2791 } 2792 } 2793 } 2794 } 2795 2796 // 2797 // Try the technology specific dispatch 2798 // 2799 String[] tagTechs = tag.getTechList(); 2800 Arrays.sort(tagTechs); 2801 2802 if (overrideIntent != null) { 2803 // There are dispatch overrides in place 2804 if (overrideTechLists != null) { 2805 for (String[] filterTechs : overrideTechLists) { 2806 if (filterMatch(tagTechs, filterTechs)) { 2807 // An override matched, send it to the foreground activity. 2808 intent = buildTagIntent(tag, msgs, 2809 NfcAdapter.ACTION_TECH_DISCOVERED); 2810 overrideIntent.send(mContext, Activity.RESULT_OK, intent); 2811 return true; 2812 } 2813 } 2814 } 2815 } else { 2816 // Standard tech dispatch path 2817 ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>(); 2818 ArrayList<ComponentInfo> registered = mTechListFilters.getComponents(); 2819 2820 // Check each registered activity to see if it matches 2821 for (ComponentInfo info : registered) { 2822 // Don't allow wild card matching 2823 if (filterMatch(tagTechs, info.techs)) { 2824 // Add the activity as a match if it's not already in the list 2825 if (!matches.contains(info.resolveInfo)) { 2826 matches.add(info.resolveInfo); 2827 } 2828 } 2829 } 2830 2831 if (matches.size() == 1) { 2832 // Single match, launch directly 2833 intent = buildTagIntent(tag, msgs, NfcAdapter.ACTION_TECH_DISCOVERED); 2834 ResolveInfo info = matches.get(0); 2835 intent.setClassName(info.activityInfo.packageName, info.activityInfo.name); 2836 try { 2837 mContext.startActivity(intent); 2838 return true; 2839 } catch (ActivityNotFoundException e) { 2840 if (DBG) Log.w(TAG, "No activities for technology handling of " + intent); 2841 } 2842 } else if (matches.size() > 1) { 2843 // Multiple matches, show a custom activity chooser dialog 2844 intent = new Intent(mContext, TechListChooserActivity.class); 2845 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2846 intent.putExtra(Intent.EXTRA_INTENT, 2847 buildTagIntent(tag, msgs, NfcAdapter.ACTION_TECH_DISCOVERED)); 2848 intent.putParcelableArrayListExtra(TechListChooserActivity.EXTRA_RESOLVE_INFOS, 2849 matches); 2850 try { 2851 mContext.startActivity(intent); 2852 return true; 2853 } catch (ActivityNotFoundException e) { 2854 if (DBG) Log.w(TAG, "No activities for technology handling of " + intent); 2855 } 2856 } else { 2857 // No matches, move on 2858 if (DBG) Log.w(TAG, "No activities for technology handling"); 2859 } 2860 } 2861 2862 // 2863 // Try the generic intent 2864 // 2865 intent = buildTagIntent(tag, msgs, NfcAdapter.ACTION_TAG_DISCOVERED); 2866 if (startDispatchActivity(intent, overrideIntent, overrideFilters, overrideTechLists)) { 2867 return true; 2868 } else { 2869 Log.e(TAG, "No tag fallback activity found for " + intent); 2870 return false; 2871 } 2872 } 2873 2874 private boolean startDispatchActivity(Intent intent, PendingIntent overrideIntent, 2875 IntentFilter[] overrideFilters, String[][] overrideTechLists) 2876 throws CanceledException { 2877 if (overrideIntent != null) { 2878 boolean found = false; 2879 if (overrideFilters == null && overrideTechLists == null) { 2880 // No filters means to always dispatch regardless of match 2881 found = true; 2882 } else if (overrideFilters != null) { 2883 for (IntentFilter filter : overrideFilters) { 2884 if (filter.match(mContext.getContentResolver(), intent, false, TAG) >= 0) { 2885 found = true; 2886 break; 2887 } 2888 } 2889 } 2890 2891 if (found) { 2892 Log.i(TAG, "Dispatching to override intent " + overrideIntent); 2893 overrideIntent.send(mContext, Activity.RESULT_OK, intent); 2894 return true; 2895 } else { 2896 return false; 2897 } 2898 } else { 2899 try { 2900 // If the current app called stopAppSwitches() then our startActivity() 2901 // can be delayed for several seconds. This happens with the default home 2902 // screen. As a system service we can override this behavior with 2903 // resumeAppSwitches() 2904 mIActivityManager.resumeAppSwitches(); 2905 } catch (RemoteException e) { } 2906 try { 2907 mContext.startActivity(intent); 2908 return true; 2909 } catch (ActivityNotFoundException e) { 2910 return false; 2911 } 2912 } 2913 } 2914 } 2915 2916 private NfcServiceHandler mHandler = new NfcServiceHandler(); 2917 2918 private class EnableDisableDiscoveryTask extends AsyncTask<Boolean, Void, Void> { 2919 @Override 2920 protected Void doInBackground(Boolean... enable) { 2921 if (enable != null && enable.length > 0 && enable[0]) { 2922 synchronized (NfcService.this) { 2923 mScreenOn = true; 2924 applyRouting(); 2925 } 2926 } else { 2927 synchronized (NfcService.this) { 2928 mWakeLock.acquire(); 2929 mScreenOn = false; 2930 applyRouting(); 2931 maybeDisconnectTarget(); 2932 mWakeLock.release(); 2933 } 2934 } 2935 return null; 2936 } 2937 } 2938 2939 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 2940 @Override 2941 public void onReceive(Context context, Intent intent) { 2942 if (intent.getAction().equals( 2943 NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) { 2944 if (DBG) Log.d(TAG, "INERNAL_TARGET_DESELECTED_ACTION"); 2945 2946 /* Restart polling loop for notification */ 2947 applyRouting(); 2948 2949 } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { 2950 // Perform discovery enable in thread to protect against ANR when the 2951 // NFC stack wedges. This is *not* the correct way to fix this issue - 2952 // configuration of the local NFC adapter should be very quick and should 2953 // be safe on the main thread, and the NFC stack should not wedge. 2954 new EnableDisableDiscoveryTask().execute(new Boolean(true)); 2955 } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 2956 // Perform discovery disable in thread to protect against ANR when the 2957 // NFC stack wedges. This is *not* the correct way to fix this issue - 2958 // configuration of the local NFC adapter should be very quick and should 2959 // be safe on the main thread, and the NFC stack should not wedge. 2960 new EnableDisableDiscoveryTask().execute(new Boolean(false)); 2961 } else if (intent.getAction().equals(ACTION_MASTER_CLEAR_NOTIFICATION)) { 2962 executeSeReset(); 2963 } else if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) { 2964 boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false); 2965 if (dataRemoved) { 2966 Uri data = intent.getData(); 2967 if (data == null) return; 2968 String packageName = data.getSchemeSpecificPart(); 2969 2970 synchronized (NfcService.this) { 2971 if (packageName.equals(mSePackageName)) { 2972 executeSeReset(); 2973 } 2974 } 2975 } 2976 } 2977 } 2978 }; 2979} 2980