1 /* 2 * Copyright (C) 2011 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 package com.android.nfc; 18 19 import com.android.nfc.echoserver.EchoServer; 20 import com.android.nfc.handover.HandoverClient; 21 import com.android.nfc.handover.HandoverManager; 22 import com.android.nfc.handover.HandoverServer; 23 import com.android.nfc.ndefpush.NdefPushClient; 24 import com.android.nfc.ndefpush.NdefPushServer; 25 import com.android.nfc.snep.SnepClient; 26 import com.android.nfc.snep.SnepMessage; 27 import com.android.nfc.snep.SnepServer; 28 29 import android.app.ActivityManager; 30 import android.app.ActivityManager.RunningTaskInfo; 31 import android.content.Context; 32 import android.content.SharedPreferences; 33 import android.content.pm.ApplicationInfo; 34 import android.content.pm.PackageManager; 35 import android.content.pm.PackageManager.NameNotFoundException; 36 import android.net.Uri; 37 import android.nfc.BeamShareData; 38 import android.nfc.IAppCallback; 39 import android.nfc.NdefMessage; 40 import android.nfc.NdefRecord; 41 import android.nfc.NfcAdapter; 42 import android.os.AsyncTask; 43 import android.os.Handler; 44 import android.os.Message; 45 import android.os.SystemClock; 46 import android.os.UserHandle; 47 import android.util.Log; 48 49 import java.io.FileDescriptor; 50 import java.io.IOException; 51 import java.io.PrintWriter; 52 import java.nio.charset.StandardCharsets; 53 import java.util.Arrays; 54 import java.util.List; 55 56 /** 57 * Interface to listen for P2P events. 58 * All callbacks are made from the UI thread. 59 */ 60 interface P2pEventListener { 61 /** 62 * Indicates a P2P device is in range. 63 * <p>onP2pInRange() and onP2pOutOfRange() will always be called 64 * alternately. 65 * <p>All other callbacks will only occur while a P2P device is in range. 66 */ 67 public void onP2pInRange(); 68 69 /** 70 * Called when a NDEF payload is prepared to send, and confirmation is 71 * required. Call Callback.onP2pSendConfirmed() to make the confirmation. 72 */ 73 public void onP2pSendConfirmationRequested(); 74 75 /** 76 * Called to indicate a send was successful. 77 */ 78 public void onP2pSendComplete(); 79 80 /** 81 * 82 * Called to indicate the link has broken while we were trying to send 83 * a message. We'll start a debounce timer for the user to get the devices 84 * back together. UI may show a hint to achieve that 85 */ 86 public void onP2pSendDebounce(); 87 88 /** 89 * Called to indicate a link has come back up after being temporarily 90 * broken, and sending is resuming 91 */ 92 public void onP2pResumeSend(); 93 94 /** 95 * Called to indicate the remote device does not support connection handover 96 */ 97 public void onP2pHandoverNotSupported(); 98 99 /** 100 * Called to indicate a receive was successful. 101 */ 102 public void onP2pReceiveComplete(boolean playSound); 103 104 /** 105 * Indicates the P2P device went out of range. 106 */ 107 public void onP2pOutOfRange(); 108 109 public interface Callback { 110 public void onP2pSendConfirmed(); 111 } 112 } 113 114 /** 115 * Manages sending and receiving NDEF message over LLCP link. 116 * Does simple debouncing of the LLCP link - so that even if the link 117 * drops and returns the user does not know. 118 */ 119 public class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback { 120 static final String TAG = "NfcP2pLinkManager"; 121 static final boolean DBG = true; 122 123 /** Include this constant as a meta-data entry in the manifest 124 * of an application to disable beaming the market/AAR link, like this: 125 * <pre>{@code 126 * <application ...> 127 * <meta-data android:name="android.nfc.disable_beam_default" 128 * android:value="true" /> 129 * </application> 130 * }</pre> 131 */ 132 static final String DISABLE_BEAM_DEFAULT = "android.nfc.disable_beam_default"; 133 134 /** Enables the LLCP EchoServer, which can be used to test the android 135 * LLCP stack against nfcpy. 136 */ 137 static final boolean ECHOSERVER_ENABLED = false; 138 139 // TODO dynamically assign SAP values 140 static final int NDEFPUSH_SAP = 0x10; 141 static final int HANDOVER_SAP = 0x14; 142 143 static final int LINK_FIRST_PDU_LIMIT_MS = 200; 144 static final int LINK_NOTHING_TO_SEND_DEBOUNCE_MS = 750; 145 static final int LINK_SEND_PENDING_DEBOUNCE_MS = 3000; 146 static final int LINK_SEND_CONFIRMED_DEBOUNCE_MS = 5000; 147 static final int LINK_SEND_COMPLETE_DEBOUNCE_MS = 250; 148 static final int MSG_DEBOUNCE_TIMEOUT = 1; 149 static final int MSG_RECEIVE_COMPLETE = 2; 150 static final int MSG_RECEIVE_HANDOVER = 3; 151 static final int MSG_SEND_COMPLETE = 4; 152 static final int MSG_START_ECHOSERVER = 5; 153 static final int MSG_STOP_ECHOSERVER = 6; 154 static final int MSG_HANDOVER_NOT_SUPPORTED = 7; 155 static final int MSG_SHOW_CONFIRMATION_UI = 8; 156 157 // values for mLinkState 158 static final int LINK_STATE_DOWN = 1; 159 static final int LINK_STATE_WAITING_PDU = 2; 160 static final int LINK_STATE_UP = 3; 161 static final int LINK_STATE_DEBOUNCE = 4; 162 163 // values for mSendState 164 static final int SEND_STATE_NOTHING_TO_SEND = 1; 165 static final int SEND_STATE_NEED_CONFIRMATION = 2; 166 static final int SEND_STATE_SENDING = 3; 167 static final int SEND_STATE_SEND_COMPLETE = 4; 168 169 // return values for doSnepProtocol 170 static final int SNEP_SUCCESS = 0; 171 static final int SNEP_FAILURE = 1; 172 173 // return values for doHandover 174 static final int HANDOVER_SUCCESS = 0; 175 static final int HANDOVER_FAILURE = 1; 176 static final int HANDOVER_UNSUPPORTED = 2; 177 178 final NdefPushServer mNdefPushServer; 179 final SnepServer mDefaultSnepServer; 180 final HandoverServer mHandoverServer; 181 final EchoServer mEchoServer; 182 final ActivityManager mActivityManager; 183 final Context mContext; 184 final P2pEventListener mEventListener; 185 final Handler mHandler; 186 final HandoverManager mHandoverManager; 187 188 final int mDefaultMiu; 189 final int mDefaultRwSize; 190 191 // Locked on NdefP2pManager.this 192 PackageManager mPackageManager; 193 int mLinkState; 194 int mSendState; // valid during LINK_STATE_UP or LINK_STATE_DEBOUNCE 195 boolean mIsSendEnabled; 196 boolean mIsReceiveEnabled; 197 NdefMessage mMessageToSend; // not valid in SEND_STATE_NOTHING_TO_SEND 198 Uri[] mUrisToSend; // not valid in SEND_STATE_NOTHING_TO_SEND 199 int mSendFlags; // not valid in SEND_STATE_NOTHING_TO_SEND 200 IAppCallback mCallbackNdef; 201 String[] mValidCallbackPackages; 202 SendTask mSendTask; 203 SharedPreferences mPrefs; 204 boolean mFirstBeam; 205 SnepClient mSnepClient; 206 HandoverClient mHandoverClient; 207 NdefPushClient mNdefPushClient; 208 ConnectTask mConnectTask; 209 boolean mLlcpServicesConnected; 210 boolean mLlcpConnectDelayed; 211 long mLastLlcpActivationTime; 212 213 public P2pLinkManager(Context context, HandoverManager handoverManager, int defaultMiu, 214 int defaultRwSize) { 215 mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback); 216 mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize); 217 mHandoverServer = new HandoverServer(HANDOVER_SAP, handoverManager, mHandoverCallback); 218 219 if (ECHOSERVER_ENABLED) { 220 mEchoServer = new EchoServer(); 221 } else { 222 mEchoServer = null; 223 } 224 mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 225 mPackageManager = context.getPackageManager(); 226 mContext = context; 227 mEventListener = new P2pEventManager(context, this); 228 mHandler = new Handler(this); 229 mLinkState = LINK_STATE_DOWN; 230 mSendState = SEND_STATE_NOTHING_TO_SEND; 231 mIsSendEnabled = false; 232 mIsReceiveEnabled = false; 233 mPrefs = context.getSharedPreferences(NfcService.PREF, Context.MODE_PRIVATE); 234 mFirstBeam = mPrefs.getBoolean(NfcService.PREF_FIRST_BEAM, true); 235 mHandoverManager = handoverManager; 236 mDefaultMiu = defaultMiu; 237 mDefaultRwSize = defaultRwSize; 238 mLlcpServicesConnected = false; 239 } 240 241 /** 242 * May be called from any thread. 243 * Assumes that NFC is already on if any parameter is true. 244 */ 245 public void enableDisable(boolean sendEnable, boolean receiveEnable) { 246 synchronized (this) { 247 if (!mIsReceiveEnabled && receiveEnable) { 248 mDefaultSnepServer.start(); 249 mNdefPushServer.start(); 250 mHandoverServer.start(); 251 if (mEchoServer != null) { 252 mHandler.sendEmptyMessage(MSG_START_ECHOSERVER); 253 } 254 } else if (mIsReceiveEnabled && !receiveEnable) { 255 if (DBG) Log.d(TAG, "enableDisable: llcp deactivate"); 256 onLlcpDeactivated (); 257 mDefaultSnepServer.stop(); 258 mNdefPushServer.stop(); 259 mHandoverServer.stop(); 260 if (mEchoServer != null) { 261 mHandler.sendEmptyMessage(MSG_STOP_ECHOSERVER); 262 } 263 } 264 mIsSendEnabled = sendEnable; 265 mIsReceiveEnabled = receiveEnable; 266 } 267 } 268 269 /** 270 * May be called from any thread. 271 * @return whether the LLCP link is in an active or debounce state 272 */ 273 public boolean isLlcpActive() { 274 synchronized (this) { 275 return mLinkState != LINK_STATE_DOWN; 276 } 277 } 278 279 /** 280 * Set NDEF callback for sending. 281 * May be called from any thread. 282 * NDEF callbacks may be set at any time (even if NFC is 283 * currently off or P2P send is currently off). They will become 284 * active as soon as P2P send is enabled. 285 */ 286 public void setNdefCallback(IAppCallback callbackNdef, int callingUid) { 287 synchronized (this) { 288 mCallbackNdef = callbackNdef; 289 mValidCallbackPackages = mPackageManager.getPackagesForUid(callingUid); 290 } 291 } 292 293 /** 294 * Must be called on UI Thread. 295 */ 296 public void onLlcpActivated() { 297 Log.i(TAG, "LLCP activated"); 298 299 synchronized (P2pLinkManager.this) { 300 if (mEchoServer != null) { 301 mEchoServer.onLlcpActivated(); 302 } 303 mLastLlcpActivationTime = SystemClock.elapsedRealtime(); 304 mLlcpConnectDelayed = false; 305 switch (mLinkState) { 306 case LINK_STATE_DOWN: 307 mLinkState = LINK_STATE_WAITING_PDU; 308 mSendState = SEND_STATE_NOTHING_TO_SEND; 309 if (DBG) Log.d(TAG, "onP2pInRange()"); 310 mEventListener.onP2pInRange(); 311 prepareMessageToSend(); 312 if (mMessageToSend != null || 313 (mUrisToSend != null && mHandoverManager.isHandoverSupported())) { 314 // Ideally we would delay showing the Beam animation until 315 // we know for certain the other side has SNEP/handover. 316 // Unfortunately, the NXP LLCP implementation has a bug that 317 // delays the first SYMM for 750ms if it is the initiator. 318 // This will cause our SNEP connect to be delayed as well, 319 // and the animation will be delayed for about a second. 320 // Alternatively, we could have used WKS as a hint to start 321 // the animation, but we are only correctly setting the WKS 322 // since Jelly Bean. 323 if ((mSendFlags & NfcAdapter.FLAG_NDEF_PUSH_NO_CONFIRM) != 0) { 324 mSendState = SEND_STATE_SENDING; 325 onP2pSendConfirmed(false); 326 } else { 327 mSendState = SEND_STATE_NEED_CONFIRMATION; 328 if (DBG) Log.d(TAG, "onP2pSendConfirmationRequested()"); 329 mEventListener.onP2pSendConfirmationRequested(); 330 } 331 } 332 break; 333 case LINK_STATE_WAITING_PDU: 334 if (DBG) Log.d(TAG, "Unexpected onLlcpActivated() in LINK_STATE_WAITING_PDU"); 335 return; 336 case LINK_STATE_UP: 337 if (DBG) Log.d(TAG, "Duplicate onLlcpActivated()"); 338 return; 339 case LINK_STATE_DEBOUNCE: 340 if (mSendState == SEND_STATE_SENDING) { 341 // Immediately connect and try to send again 342 mLinkState = LINK_STATE_UP; 343 connectLlcpServices(); 344 } else { 345 mLinkState = LINK_STATE_WAITING_PDU; 346 } 347 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 348 break; 349 } 350 } 351 } 352 353 /** 354 * Must be called on UI Thread. 355 */ 356 public void onLlcpFirstPacketReceived() { 357 synchronized (P2pLinkManager.this) { 358 long totalTime = SystemClock.elapsedRealtime() - mLastLlcpActivationTime; 359 if (DBG) Log.d(TAG, "Took " + Long.toString(totalTime) + " to get first LLCP PDU"); 360 switch (mLinkState) { 361 case LINK_STATE_UP: 362 if (DBG) Log.d(TAG, "Dropping first LLCP packet received"); 363 break; 364 case LINK_STATE_DOWN: 365 case LINK_STATE_DEBOUNCE: 366 Log.e(TAG, "Unexpected first LLCP packet received"); 367 break; 368 case LINK_STATE_WAITING_PDU: 369 mLinkState = LINK_STATE_UP; 370 if (mSendState == SEND_STATE_NOTHING_TO_SEND) 371 break; 372 if (totalTime < LINK_FIRST_PDU_LIMIT_MS || mSendState == SEND_STATE_SENDING) { 373 connectLlcpServices(); 374 } else { 375 mLlcpConnectDelayed = true; 376 } 377 break; 378 } 379 } 380 } 381 382 public void onUserSwitched() { 383 // Update the cached package manager in case of user switch 384 synchronized (P2pLinkManager.this) { 385 try { 386 mPackageManager = mContext.createPackageContextAsUser("android", 0, 387 new UserHandle(ActivityManager.getCurrentUser())).getPackageManager(); 388 } catch (NameNotFoundException e) { 389 Log.e(TAG, "Failed to retrieve PackageManager for user"); 390 } 391 } 392 } 393 394 void prepareMessageToSend() { 395 synchronized (P2pLinkManager.this) { 396 if (!mIsSendEnabled) { 397 mMessageToSend = null; 398 mUrisToSend = null; 399 return; 400 } 401 402 String runningPackage = null; 403 List<RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1); 404 if (tasks.size() > 0) { 405 runningPackage = tasks.get(0).topActivity.getPackageName(); 406 } 407 408 if (runningPackage == null) { 409 Log.e(TAG, "Could not determine running package."); 410 mMessageToSend = null; 411 mUrisToSend = null; 412 return; 413 } 414 415 // Try application callback first 416 if (mCallbackNdef != null) { 417 // Check to see if the package currently running 418 // is the one that registered any callbacks 419 boolean callbackValid = false; 420 421 if (mValidCallbackPackages != null) { 422 for (String pkg : mValidCallbackPackages) { 423 if (pkg.equals(runningPackage)) { 424 callbackValid = true; 425 break; 426 } 427 } 428 } 429 430 if (callbackValid) { 431 try { 432 BeamShareData shareData = mCallbackNdef.createBeamShareData(); 433 mMessageToSend = shareData.ndefMessage; 434 mUrisToSend = shareData.uris; 435 mSendFlags = shareData.flags; 436 return; 437 } catch (Exception e) { 438 Log.e(TAG, "Failed NDEF callback: " + e.getMessage()); 439 } 440 } else { 441 // This is not necessarily an error - we no longer unset callbacks from 442 // the app process itself (to prevent IPC calls on every pause). 443 // Hence it may simply be a stale callback. 444 if (DBG) Log.d(TAG, "Last registered callback is not running in the foreground."); 445 } 446 } 447 448 // fall back to default NDEF for the foreground activity, unless the 449 // application disabled this explicitly in their manifest. 450 if (beamDefaultDisabled(runningPackage)) { 451 Log.d(TAG, "Disabling default Beam behavior"); 452 mMessageToSend = null; 453 mUrisToSend = null; 454 } else { 455 mMessageToSend = createDefaultNdef(runningPackage); 456 mUrisToSend = null; 457 } 458 459 if (DBG) Log.d(TAG, "mMessageToSend = " + mMessageToSend); 460 if (DBG) Log.d(TAG, "mUrisToSend = " + mUrisToSend); 461 } 462 } 463 464 boolean beamDefaultDisabled(String pkgName) { 465 try { 466 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkgName, 467 PackageManager.GET_META_DATA); 468 if (ai == null || ai.metaData == null) { 469 return false; 470 } 471 return ai.metaData.getBoolean(DISABLE_BEAM_DEFAULT); 472 } catch (NameNotFoundException e) { 473 return false; 474 } 475 } 476 477 NdefMessage createDefaultNdef(String pkgName) { 478 NdefRecord appUri = NdefRecord.createUri(Uri.parse( 479 "http://play.google.com/store/apps/details?id=" + pkgName + "&feature=beam")); 480 NdefRecord appRecord = NdefRecord.createApplicationRecord(pkgName); 481 return new NdefMessage(new NdefRecord[] { appUri, appRecord }); 482 } 483 484 void disconnectLlcpServices() { 485 synchronized (this) { 486 if (mConnectTask != null) { 487 mConnectTask.cancel(true); 488 mConnectTask = null; 489 } 490 // Close any already connected LLCP clients 491 if (mNdefPushClient != null) { 492 mNdefPushClient.close(); 493 mNdefPushClient = null; 494 } 495 if (mSnepClient != null) { 496 mSnepClient.close(); 497 mSnepClient = null; 498 } 499 if (mHandoverClient != null) { 500 mHandoverClient.close(); 501 mHandoverClient = null; 502 } 503 mLlcpServicesConnected = false; 504 } 505 } 506 507 /** 508 * Must be called on UI Thread. 509 */ 510 public void onLlcpDeactivated() { 511 Log.i(TAG, "LLCP deactivated."); 512 synchronized (this) { 513 if (mEchoServer != null) { 514 mEchoServer.onLlcpDeactivated(); 515 } 516 517 switch (mLinkState) { 518 case LINK_STATE_DOWN: 519 case LINK_STATE_DEBOUNCE: 520 Log.i(TAG, "Duplicate onLlcpDectivated()"); 521 break; 522 case LINK_STATE_WAITING_PDU: 523 case LINK_STATE_UP: 524 // Debounce 525 mLinkState = LINK_STATE_DEBOUNCE; 526 int debounceTimeout = 0; 527 switch (mSendState) { 528 case SEND_STATE_NOTHING_TO_SEND: 529 debounceTimeout = 0; 530 break; 531 case SEND_STATE_NEED_CONFIRMATION: 532 debounceTimeout = LINK_SEND_PENDING_DEBOUNCE_MS; 533 break; 534 case SEND_STATE_SENDING: 535 debounceTimeout = LINK_SEND_CONFIRMED_DEBOUNCE_MS; 536 break; 537 case SEND_STATE_SEND_COMPLETE: 538 debounceTimeout = LINK_SEND_COMPLETE_DEBOUNCE_MS; 539 break; 540 } 541 mHandler.sendEmptyMessageDelayed(MSG_DEBOUNCE_TIMEOUT, debounceTimeout); 542 if (mSendState == SEND_STATE_SENDING) { 543 Log.e(TAG, "onP2pSendDebounce()"); 544 mEventListener.onP2pSendDebounce(); 545 } 546 cancelSendNdefMessage(); 547 disconnectLlcpServices(); 548 break; 549 } 550 } 551 } 552 553 void onHandoverUnsupported() { 554 mHandler.sendEmptyMessage(MSG_HANDOVER_NOT_SUPPORTED); 555 } 556 557 void onSendComplete(NdefMessage msg, long elapsedRealtime) { 558 if (mFirstBeam) { 559 EventLogTags.writeNfcFirstShare(); 560 mPrefs.edit().putBoolean(NfcService.PREF_FIRST_BEAM, false).apply(); 561 mFirstBeam = false; 562 } 563 EventLogTags.writeNfcShare(getMessageSize(msg), getMessageTnf(msg), getMessageType(msg), 564 getMessageAarPresent(msg), (int) elapsedRealtime); 565 // Make callbacks on UI thread 566 mHandler.sendEmptyMessage(MSG_SEND_COMPLETE); 567 } 568 569 void sendNdefMessage() { 570 synchronized (this) { 571 cancelSendNdefMessage(); 572 mSendTask = new SendTask(); 573 mSendTask.execute(); 574 } 575 } 576 577 void cancelSendNdefMessage() { 578 synchronized (P2pLinkManager.this) { 579 if (mSendTask != null) { 580 mSendTask.cancel(true); 581 } 582 } 583 } 584 585 void connectLlcpServices() { 586 synchronized (P2pLinkManager.this) { 587 if (mConnectTask != null) { 588 Log.e(TAG, "Still had a reference to mConnectTask!"); 589 } 590 mConnectTask = new ConnectTask(); 591 mConnectTask.execute(); 592 } 593 } 594 595 // Must be called on UI-thread 596 void onLlcpServicesConnected() { 597 if (DBG) Log.d(TAG, "onLlcpServicesConnected"); 598 synchronized (P2pLinkManager.this) { 599 if (mLinkState != LINK_STATE_UP) { 600 return; 601 } 602 mLlcpServicesConnected = true; 603 if (mSendState == SEND_STATE_SENDING) { 604 // FIXME Keep state to make sure this is only called when in debounce 605 // and remove logic in P2pEventManager to keep track. 606 mEventListener.onP2pResumeSend(); 607 sendNdefMessage(); 608 } else { 609 // User still needs to confirm, or we may have received something already. 610 } 611 } 612 } 613 614 final class ConnectTask extends AsyncTask<Void, Void, Boolean> { 615 @Override 616 protected void onPostExecute(Boolean result) { 617 if (isCancelled()) { 618 if (DBG) Log.d(TAG, "ConnectTask was cancelled"); 619 return; 620 } 621 if (result) { 622 onLlcpServicesConnected(); 623 } else { 624 Log.e(TAG, "Could not connect required NFC transports"); 625 } 626 } 627 628 @Override 629 protected Boolean doInBackground(Void... params) { 630 boolean needsHandover = false; 631 boolean needsNdef = false; 632 boolean success = false; 633 HandoverClient handoverClient = null; 634 SnepClient snepClient = null; 635 NdefPushClient nppClient = null; 636 637 synchronized(P2pLinkManager.this) { 638 if (mUrisToSend != null) { 639 needsHandover = true; 640 } 641 642 if (mMessageToSend != null) { 643 needsNdef = true; 644 } 645 } 646 // We know either is requested - otherwise this task 647 // wouldn't have been started. 648 if (needsHandover) { 649 handoverClient = new HandoverClient(); 650 try { 651 handoverClient.connect(); 652 success = true; // Regardless of NDEF result 653 } catch (IOException e) { 654 handoverClient = null; 655 } 656 } 657 658 if (needsNdef || (needsHandover && handoverClient == null)) { 659 snepClient = new SnepClient(); 660 try { 661 snepClient.connect(); 662 success = true; 663 } catch (IOException e) { 664 snepClient = null; 665 } 666 667 if (!success) { 668 nppClient = new NdefPushClient(); 669 try { 670 nppClient.connect(); 671 success = true; 672 } catch (IOException e) { 673 nppClient = null; 674 } 675 } 676 } 677 678 synchronized (P2pLinkManager.this) { 679 if (isCancelled()) { 680 // Cancelled by onLlcpDeactivated on UI thread 681 if (handoverClient != null) { 682 handoverClient.close(); 683 } 684 if (snepClient != null) { 685 snepClient.close(); 686 } 687 if (nppClient != null) { 688 nppClient.close(); 689 } 690 return false; 691 } else { 692 // Once assigned, these are the responsibility of 693 // the code on the UI thread to release - typically 694 // through onLlcpDeactivated(). 695 mHandoverClient = handoverClient; 696 mSnepClient = snepClient; 697 mNdefPushClient = nppClient; 698 return success; 699 } 700 } 701 } 702 }; 703 704 final class SendTask extends AsyncTask<Void, Void, Void> { 705 NdefPushClient nppClient; 706 SnepClient snepClient; 707 HandoverClient handoverClient; 708 709 int doHandover(Uri[] uris) throws IOException { 710 NdefMessage response = null; 711 NdefMessage request = mHandoverManager.createHandoverRequestMessage(); 712 if (request != null) { 713 if (handoverClient != null) { 714 response = handoverClient.sendHandoverRequest(request); 715 } 716 if (response == null && snepClient != null) { 717 // Remote device may not support handover service, 718 // try the (deprecated) SNEP GET implementation 719 // for devices running Android 4.1 720 SnepMessage snepResponse = snepClient.get(request); 721 response = snepResponse.getNdefMessage(); 722 } 723 if (response == null) { 724 return HANDOVER_UNSUPPORTED; 725 } 726 } else { 727 return HANDOVER_UNSUPPORTED; 728 } 729 mHandoverManager.doHandoverUri(uris, response); 730 return HANDOVER_SUCCESS; 731 } 732 733 int doSnepProtocol(NdefMessage msg) throws IOException { 734 if (msg != null) { 735 snepClient.put(msg); 736 return SNEP_SUCCESS; 737 } else { 738 return SNEP_FAILURE; 739 } 740 } 741 742 @Override 743 public Void doInBackground(Void... args) { 744 NdefMessage m; 745 Uri[] uris; 746 boolean result = false; 747 748 synchronized (P2pLinkManager.this) { 749 if (mLinkState != LINK_STATE_UP || mSendState != SEND_STATE_SENDING) { 750 return null; 751 } 752 m = mMessageToSend; 753 uris = mUrisToSend; 754 snepClient = mSnepClient; 755 handoverClient = mHandoverClient; 756 nppClient = mNdefPushClient; 757 } 758 759 long time = SystemClock.elapsedRealtime(); 760 761 if (uris != null) { 762 if (DBG) Log.d(TAG, "Trying handover request"); 763 try { 764 int handoverResult = doHandover(uris); 765 switch (handoverResult) { 766 case HANDOVER_SUCCESS: 767 result = true; 768 break; 769 case HANDOVER_FAILURE: 770 result = false; 771 break; 772 case HANDOVER_UNSUPPORTED: 773 result = false; 774 onHandoverUnsupported(); 775 break; 776 } 777 } catch (IOException e) { 778 result = false; 779 } 780 } 781 782 if (!result && m != null && snepClient != null) { 783 if (DBG) Log.d(TAG, "Sending ndef via SNEP"); 784 try { 785 int snepResult = doSnepProtocol(m); 786 switch (snepResult) { 787 case SNEP_SUCCESS: 788 result = true; 789 break; 790 case SNEP_FAILURE: 791 result = false; 792 break; 793 default: 794 result = false; 795 } 796 } catch (IOException e) { 797 result = false; 798 } 799 } 800 801 if (!result && m != null && nppClient != null) { 802 result = nppClient.push(m); 803 } 804 805 time = SystemClock.elapsedRealtime() - time; 806 if (DBG) Log.d(TAG, "SendTask result=" + result + ", time ms=" + time); 807 if (result) { 808 onSendComplete(m, time); 809 } 810 811 return null; 812 } 813 }; 814 815 816 final HandoverServer.Callback mHandoverCallback = new HandoverServer.Callback() { 817 @Override 818 public void onHandoverRequestReceived() { 819 onReceiveHandover(); 820 } 821 }; 822 823 final NdefPushServer.Callback mNppCallback = new NdefPushServer.Callback() { 824 @Override 825 public void onMessageReceived(NdefMessage msg) { 826 onReceiveComplete(msg); 827 } 828 }; 829 830 final SnepServer.Callback mDefaultSnepCallback = new SnepServer.Callback() { 831 @Override 832 public SnepMessage doPut(NdefMessage msg) { 833 onReceiveComplete(msg); 834 return SnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS); 835 } 836 837 @Override 838 public SnepMessage doGet(int acceptableLength, NdefMessage msg) { 839 // The NFC Forum Default SNEP server is not allowed to respond to 840 // SNEP GET requests - see SNEP 1.0 TS section 6.1. However, 841 // since Android 4.1 used the NFC Forum default server to 842 // implement connection handover, we will support this 843 // until we can deprecate it. 844 NdefMessage response = mHandoverManager.tryHandoverRequest(msg); 845 if (response != null) { 846 onReceiveHandover(); 847 return SnepMessage.getSuccessResponse(response); 848 } else { 849 return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED); 850 } 851 } 852 }; 853 854 void onReceiveHandover() { 855 mHandler.obtainMessage(MSG_RECEIVE_HANDOVER).sendToTarget(); 856 } 857 858 void onReceiveComplete(NdefMessage msg) { 859 EventLogTags.writeNfcNdefReceived(getMessageSize(msg), getMessageTnf(msg), 860 getMessageType(msg), getMessageAarPresent(msg)); 861 // Make callbacks on UI thread 862 mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget(); 863 } 864 865 @Override 866 public boolean handleMessage(Message msg) { 867 switch (msg.what) { 868 case MSG_START_ECHOSERVER: 869 synchronized (this) { 870 mEchoServer.start(); 871 break; 872 } 873 case MSG_STOP_ECHOSERVER: 874 synchronized (this) { 875 mEchoServer.stop(); 876 break; 877 } 878 case MSG_DEBOUNCE_TIMEOUT: 879 synchronized (this) { 880 if (mLinkState != LINK_STATE_DEBOUNCE) { 881 break; 882 } 883 if (mSendState == SEND_STATE_SENDING) { 884 EventLogTags.writeNfcShareFail(getMessageSize(mMessageToSend), 885 getMessageTnf(mMessageToSend), getMessageType(mMessageToSend), 886 getMessageAarPresent(mMessageToSend)); 887 } 888 if (DBG) Log.d(TAG, "Debounce timeout"); 889 mLinkState = LINK_STATE_DOWN; 890 mSendState = SEND_STATE_NOTHING_TO_SEND; 891 mMessageToSend = null; 892 mUrisToSend = null; 893 if (DBG) Log.d(TAG, "onP2pOutOfRange()"); 894 mEventListener.onP2pOutOfRange(); 895 } 896 break; 897 case MSG_RECEIVE_HANDOVER: 898 // We're going to do a handover request 899 synchronized (this) { 900 if (mLinkState == LINK_STATE_DOWN) { 901 break; 902 } 903 if (mSendState == SEND_STATE_SENDING) { 904 cancelSendNdefMessage(); 905 } 906 mSendState = SEND_STATE_NOTHING_TO_SEND; 907 if (DBG) Log.d(TAG, "onP2pReceiveComplete()"); 908 mEventListener.onP2pReceiveComplete(false); 909 } 910 break; 911 case MSG_RECEIVE_COMPLETE: 912 NdefMessage m = (NdefMessage) msg.obj; 913 synchronized (this) { 914 if (mLinkState == LINK_STATE_DOWN) { 915 break; 916 } 917 if (mSendState == SEND_STATE_SENDING) { 918 cancelSendNdefMessage(); 919 } 920 mSendState = SEND_STATE_NOTHING_TO_SEND; 921 if (DBG) Log.d(TAG, "onP2pReceiveComplete()"); 922 mEventListener.onP2pReceiveComplete(true); 923 NfcService.getInstance().sendMockNdefTag(m); 924 } 925 break; 926 case MSG_HANDOVER_NOT_SUPPORTED: 927 synchronized (P2pLinkManager.this) { 928 mSendTask = null; 929 930 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 931 break; 932 } 933 mSendState = SEND_STATE_NOTHING_TO_SEND; 934 if (DBG) Log.d(TAG, "onP2pHandoverNotSupported()"); 935 mEventListener.onP2pHandoverNotSupported(); 936 } 937 break; 938 case MSG_SEND_COMPLETE: 939 synchronized (P2pLinkManager.this) { 940 mSendTask = null; 941 942 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 943 break; 944 } 945 mSendState = SEND_STATE_SEND_COMPLETE; 946 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 947 if (DBG) Log.d(TAG, "onP2pSendComplete()"); 948 mEventListener.onP2pSendComplete(); 949 if (mCallbackNdef != null) { 950 try { 951 mCallbackNdef.onNdefPushComplete(); 952 } catch (Exception e) { 953 Log.e(TAG, "Failed NDEF completed callback: " + e.getMessage()); 954 } 955 } 956 } 957 break; 958 } 959 return true; 960 } 961 962 int getMessageSize(NdefMessage msg) { 963 if (msg != null) { 964 return msg.toByteArray().length; 965 } else { 966 return 0; 967 } 968 } 969 970 int getMessageTnf(NdefMessage msg) { 971 if (msg == null) { 972 return NdefRecord.TNF_EMPTY; 973 } 974 NdefRecord records[] = msg.getRecords(); 975 if (records == null || records.length == 0) { 976 return NdefRecord.TNF_EMPTY; 977 } 978 return records[0].getTnf(); 979 } 980 981 String getMessageType(NdefMessage msg) { 982 if (msg == null) { 983 return "null"; 984 } 985 NdefRecord records[] = msg.getRecords(); 986 if (records == null || records.length == 0) { 987 return "null"; 988 } 989 NdefRecord record = records[0]; 990 switch (record.getTnf()) { 991 case NdefRecord.TNF_ABSOLUTE_URI: 992 // The actual URI is in the type field, don't log it 993 return "uri"; 994 case NdefRecord.TNF_EXTERNAL_TYPE: 995 case NdefRecord.TNF_MIME_MEDIA: 996 case NdefRecord.TNF_WELL_KNOWN: 997 return new String(record.getType(), StandardCharsets.UTF_8); 998 default: 999 return "unknown"; 1000 } 1001 } 1002 1003 int getMessageAarPresent(NdefMessage msg) { 1004 if (msg == null) { 1005 return 0; 1006 } 1007 NdefRecord records[] = msg.getRecords(); 1008 if (records == null) { 1009 return 0; 1010 } 1011 for (NdefRecord record : records) { 1012 if (record.getTnf() == NdefRecord.TNF_EXTERNAL_TYPE && 1013 Arrays.equals(NdefRecord.RTD_ANDROID_APP, record.getType())) { 1014 return 1; 1015 } 1016 } 1017 return 0; 1018 } 1019 1020 @Override 1021 public void onP2pSendConfirmed() { 1022 onP2pSendConfirmed(true); 1023 } 1024 1025 private void onP2pSendConfirmed(boolean requireConfirmation) { 1026 if (DBG) Log.d(TAG, "onP2pSendConfirmed()"); 1027 synchronized (this) { 1028 if (mLinkState == LINK_STATE_DOWN || (requireConfirmation 1029 && mSendState != SEND_STATE_NEED_CONFIRMATION)) { 1030 return; 1031 } 1032 mSendState = SEND_STATE_SENDING; 1033 if (mLinkState == LINK_STATE_WAITING_PDU) { 1034 // We could decide to wait for the first PDU here; but 1035 // that makes us vulnerable to cases where for some reason 1036 // this event is not propagated up by the stack. Instead, 1037 // try to connect now. 1038 mLinkState = LINK_STATE_UP; 1039 connectLlcpServices(); 1040 } else if (mLinkState == LINK_STATE_UP && mLlcpServicesConnected) { 1041 sendNdefMessage(); 1042 } else if (mLinkState == LINK_STATE_UP && mLlcpConnectDelayed) { 1043 // Connect was delayed to interop with pre-MR2 stacks; send connect now. 1044 connectLlcpServices(); 1045 } else if (mLinkState == LINK_STATE_DEBOUNCE) { 1046 // Restart debounce timeout 1047 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 1048 mHandler.sendEmptyMessageDelayed(MSG_DEBOUNCE_TIMEOUT, 1049 LINK_SEND_CONFIRMED_DEBOUNCE_MS); 1050 // Tell user to tap devices again 1051 mEventListener.onP2pSendDebounce(); 1052 } 1053 } 1054 } 1055 1056 static String sendStateToString(int state) { 1057 switch (state) { 1058 case SEND_STATE_NOTHING_TO_SEND: 1059 return "SEND_STATE_NOTHING_TO_SEND"; 1060 case SEND_STATE_NEED_CONFIRMATION: 1061 return "SEND_STATE_NEED_CONFIRMATION"; 1062 case SEND_STATE_SENDING: 1063 return "SEND_STATE_SENDING"; 1064 default: 1065 return "<error>"; 1066 } 1067 } 1068 1069 static String linkStateToString(int state) { 1070 switch (state) { 1071 case LINK_STATE_DOWN: 1072 return "LINK_STATE_DOWN"; 1073 case LINK_STATE_DEBOUNCE: 1074 return "LINK_STATE_DEBOUNCE"; 1075 case LINK_STATE_UP: 1076 return "LINK_STATE_UP"; 1077 case LINK_STATE_WAITING_PDU: 1078 return "LINK_STATE_WAITING_PDU"; 1079 default: 1080 return "<error>"; 1081 } 1082 } 1083 1084 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1085 synchronized (this) { 1086 pw.println("mIsSendEnabled=" + mIsSendEnabled); 1087 pw.println("mIsReceiveEnabled=" + mIsReceiveEnabled); 1088 pw.println("mLinkState=" + linkStateToString(mLinkState)); 1089 pw.println("mSendState=" + sendStateToString(mSendState)); 1090 1091 pw.println("mCallbackNdef=" + mCallbackNdef); 1092 pw.println("mMessageToSend=" + mMessageToSend); 1093 pw.println("mUrisToSend=" + mUrisToSend); 1094 } 1095 } 1096 } 1097