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 android.content.Intent; 20 import android.content.pm.UserInfo; 21 22 import com.android.nfc.beam.BeamManager; 23 import com.android.nfc.beam.BeamSendService; 24 import com.android.nfc.beam.BeamTransferRecord; 25 26 import android.os.UserManager; 27 import com.android.nfc.sneptest.ExtDtaSnepServer; 28 import com.android.nfc.sneptest.DtaSnepClient; 29 import com.android.nfc.echoserver.EchoServer; 30 import com.android.nfc.handover.HandoverClient; 31 import com.android.nfc.handover.HandoverDataParser; 32 import com.android.nfc.handover.HandoverServer; 33 import com.android.nfc.ndefpush.NdefPushClient; 34 import com.android.nfc.ndefpush.NdefPushServer; 35 import com.android.nfc.snep.SnepClient; 36 import com.android.nfc.snep.SnepMessage; 37 import com.android.nfc.snep.SnepServer; 38 39 import android.content.Context; 40 import android.content.SharedPreferences; 41 import android.content.pm.ApplicationInfo; 42 import android.content.pm.PackageManager; 43 import android.content.pm.PackageManager.NameNotFoundException; 44 import android.net.Uri; 45 import android.nfc.BeamShareData; 46 import android.nfc.IAppCallback; 47 import android.nfc.NdefMessage; 48 import android.nfc.NdefRecord; 49 import android.nfc.NfcAdapter; 50 import android.os.AsyncTask; 51 import android.os.Handler; 52 import android.os.Message; 53 import android.os.SystemClock; 54 import android.os.UserHandle; 55 import android.util.Log; 56 import java.io.FileDescriptor; 57 import java.io.IOException; 58 import java.io.PrintWriter; 59 import java.nio.charset.StandardCharsets; 60 import java.util.Arrays; 61 import java.util.List; 62 import java.io.UnsupportedEncodingException; 63 64 import android.util.StatsLog; 65 /** 66 * Interface to listen for P2P events. 67 * All callbacks are made from the UI thread. 68 */ 69 interface P2pEventListener { 70 /** 71 * Indicates the user has expressed an intent to share 72 * over NFC, but a remote device has not come into range 73 * yet. Prompt the user to NFC tap. 74 */ onP2pNfcTapRequested()75 public void onP2pNfcTapRequested(); 76 77 /** 78 * Indicates the user has expressed an intent to share over 79 * NFC, but the link hasn't come up yet and we no longer 80 * want to wait for it 81 */ onP2pTimeoutWaitingForLink()82 public void onP2pTimeoutWaitingForLink(); 83 84 /** 85 * Indicates a P2P device is in range. 86 * <p>onP2pInRange() and onP2pOutOfRange() will always be called 87 * alternately. 88 */ onP2pInRange()89 public void onP2pInRange(); 90 91 /** 92 * Called when a NDEF payload is prepared to send, and confirmation is 93 * required. Call Callback.onP2pSendConfirmed() to make the confirmation. 94 */ onP2pSendConfirmationRequested()95 public void onP2pSendConfirmationRequested(); 96 97 /** 98 * Called to indicate a send was successful. 99 */ onP2pSendComplete()100 public void onP2pSendComplete(); 101 102 /** 103 * 104 * Called to indicate the link has broken while we were trying to send 105 * a message. We'll start a debounce timer for the user to get the devices 106 * back together. UI may show a hint to achieve that 107 */ onP2pSendDebounce()108 public void onP2pSendDebounce(); 109 110 /** 111 * Called to indicate a link has come back up after being temporarily 112 * broken, and sending is resuming 113 */ onP2pResumeSend()114 public void onP2pResumeSend(); 115 116 /** 117 * Called to indicate the remote device does not support connection handover 118 */ onP2pHandoverNotSupported()119 public void onP2pHandoverNotSupported(); 120 121 /** 122 * Called to indicate the device is busy with another handover transfer 123 */ onP2pHandoverBusy()124 public void onP2pHandoverBusy(); 125 126 /** 127 * Called to indicate a receive was successful. 128 */ onP2pReceiveComplete(boolean playSound)129 public void onP2pReceiveComplete(boolean playSound); 130 131 /** 132 * Indicates the P2P device went out of range. 133 */ onP2pOutOfRange()134 public void onP2pOutOfRange(); 135 136 /** 137 * Indicates the P2P Beam UI is in idle mode. 138 */ isP2pIdle()139 public boolean isP2pIdle(); 140 141 public interface Callback { onP2pSendConfirmed()142 public void onP2pSendConfirmed(); onP2pCanceled()143 public void onP2pCanceled(); 144 } 145 } 146 147 /** 148 * Manages sending and receiving NDEF message over LLCP link. 149 * Does simple debouncing of the LLCP link - so that even if the link 150 * drops and returns the user does not know. 151 */ 152 class P2pLinkManager implements Handler.Callback, P2pEventListener.Callback { 153 static final String TAG = "NfcP2pLinkManager"; 154 static final boolean DBG = true; 155 156 /** Include this constant as a meta-data entry in the manifest 157 * of an application to disable beaming the market/AAR link, like this: 158 * <pre>{@code 159 * <application ...> 160 * <meta-data android:name="android.nfc.disable_beam_default" 161 * android:value="true" /> 162 * </application> 163 * }</pre> 164 */ 165 static final String DISABLE_BEAM_DEFAULT = "android.nfc.disable_beam_default"; 166 167 /** Enables the LLCP EchoServer, which can be used to test the android 168 * LLCP stack against nfcpy. 169 */ 170 static final boolean ECHOSERVER_ENABLED = false; 171 172 // TODO dynamically assign SAP values 173 static final int NDEFPUSH_SAP = 0x10; 174 static final int HANDOVER_SAP = 0x14; 175 176 static final int LINK_SEND_PENDING_DEBOUNCE_MS = 3000; 177 static final int LINK_SEND_CONFIRMED_DEBOUNCE_MS = 5000; 178 static final int LINK_SEND_COMPLETE_DEBOUNCE_MS = 500; 179 static final int LINK_SEND_CANCELED_DEBOUNCE_MS = 250; 180 181 // The amount of time we wait for the link to come up 182 // after a user has manually invoked Beam. 183 static final int WAIT_FOR_LINK_TIMEOUT_MS = 10000; 184 185 static final int MSG_DEBOUNCE_TIMEOUT = 1; 186 static final int MSG_RECEIVE_COMPLETE = 2; 187 static final int MSG_RECEIVE_HANDOVER = 3; 188 static final int MSG_SEND_COMPLETE = 4; 189 static final int MSG_START_ECHOSERVER = 5; 190 static final int MSG_STOP_ECHOSERVER = 6; 191 static final int MSG_HANDOVER_NOT_SUPPORTED = 7; 192 static final int MSG_SHOW_CONFIRMATION_UI = 8; 193 static final int MSG_WAIT_FOR_LINK_TIMEOUT = 9; 194 static final int MSG_HANDOVER_BUSY = 10; 195 196 // values for mLinkState 197 static final int LINK_STATE_DOWN = 1; 198 static final int LINK_STATE_UP = 2; 199 static final int LINK_STATE_DEBOUNCE = 3; 200 201 // values for mSendState 202 static final int SEND_STATE_NOTHING_TO_SEND = 1; 203 static final int SEND_STATE_NEED_CONFIRMATION = 2; 204 static final int SEND_STATE_PENDING = 3; 205 static final int SEND_STATE_SENDING = 4; 206 static final int SEND_STATE_COMPLETE = 5; 207 static final int SEND_STATE_CANCELED = 6; 208 209 // return values for doSnepProtocol 210 static final int SNEP_SUCCESS = 0; 211 static final int SNEP_FAILURE = 1; 212 213 // return values for doHandover 214 static final int HANDOVER_SUCCESS = 0; 215 static final int HANDOVER_FAILURE = 1; 216 static final int HANDOVER_UNSUPPORTED = 2; 217 static final int HANDOVER_BUSY = 3; 218 219 final NdefPushServer mNdefPushServer; 220 final SnepServer mDefaultSnepServer; 221 final HandoverServer mHandoverServer; 222 final EchoServer mEchoServer; 223 final Context mContext; 224 final P2pEventListener mEventListener; 225 final Handler mHandler; 226 final HandoverDataParser mHandoverDataParser; 227 final ForegroundUtils mForegroundUtils; 228 229 final int mDefaultMiu; 230 final int mDefaultRwSize; 231 232 // Locked on NdefP2pManager.this 233 PackageManager mPackageManager; 234 int mLinkState; 235 int mSendState; // valid during LINK_STATE_UP or LINK_STATE_DEBOUNCE 236 boolean mIsSendEnabled; 237 boolean mIsReceiveEnabled; 238 NdefMessage mMessageToSend; // not valid in SEND_STATE_NOTHING_TO_SEND 239 Uri[] mUrisToSend; // not valid in SEND_STATE_NOTHING_TO_SEND 240 UserHandle mUserHandle; // not valid in SEND_STATE_NOTHING_TO_SEND 241 int mSendFlags; // not valid in SEND_STATE_NOTHING_TO_SEND 242 IAppCallback mCallbackNdef; 243 int mNdefCallbackUid; 244 SendTask mSendTask; 245 SharedPreferences mPrefs; 246 SnepClient mSnepClient; 247 HandoverClient mHandoverClient; 248 NdefPushClient mNdefPushClient; 249 ConnectTask mConnectTask; 250 boolean mLlcpServicesConnected; 251 long mLastLlcpActivationTime; 252 byte mPeerLlcpVersion; 253 // for DTA Mode 254 private int mDtaMiu; 255 private int mDtaRwSize; 256 private int mServiceSap; 257 private int mTestCaseID; 258 private String mServiceName; 259 private ExtDtaSnepServer mExtDtaSnepServer = null; 260 private DtaSnepClient mDtaSnepClient = null; 261 private boolean mClientEnabled = false; 262 private boolean mServerEnabled = false; 263 private boolean mExtDtaSnepServerRunning = false; 264 private boolean mPutBeforeGet = false; 265 P2pLinkManager(Context context, HandoverDataParser handoverDataParser, int defaultMiu, int defaultRwSize)266 public P2pLinkManager(Context context, HandoverDataParser handoverDataParser, int defaultMiu, 267 int defaultRwSize) { 268 mNdefPushServer = new NdefPushServer(NDEFPUSH_SAP, mNppCallback); 269 mDefaultSnepServer = new SnepServer(mDefaultSnepCallback, defaultMiu, defaultRwSize); 270 mHandoverServer = new HandoverServer(context, HANDOVER_SAP, handoverDataParser, mHandoverCallback); 271 272 if (ECHOSERVER_ENABLED) { 273 mEchoServer = new EchoServer(); 274 } else { 275 mEchoServer = null; 276 } 277 mPackageManager = context.getPackageManager(); 278 mContext = context; 279 mEventListener = new P2pEventManager(context, this); 280 mHandler = new Handler(this); 281 mLinkState = LINK_STATE_DOWN; 282 mSendState = SEND_STATE_NOTHING_TO_SEND; 283 mIsSendEnabled = false; 284 mIsReceiveEnabled = false; 285 mPrefs = context.getSharedPreferences(NfcService.PREF, Context.MODE_PRIVATE); 286 mHandoverDataParser = handoverDataParser; 287 mDefaultMiu = defaultMiu; 288 mDefaultRwSize = defaultRwSize; 289 mLlcpServicesConnected = false; 290 mNdefCallbackUid = -1; 291 mForegroundUtils = ForegroundUtils.getInstance(); 292 } 293 294 /** 295 * May be called from any thread. 296 * Assumes that NFC is already on if any parameter is true. 297 */ enableDisable(boolean sendEnable, boolean receiveEnable)298 public void enableDisable(boolean sendEnable, boolean receiveEnable) { 299 synchronized (this) { 300 if (!mIsReceiveEnabled && receiveEnable) { 301 mDefaultSnepServer.start(); 302 mNdefPushServer.start(); 303 mHandoverServer.start(); 304 if (mEchoServer != null) { 305 mHandler.sendEmptyMessage(MSG_START_ECHOSERVER); 306 } 307 } else if (mIsReceiveEnabled && !receiveEnable) { 308 if (DBG) Log.d(TAG, "enableDisable: llcp deactivate"); 309 onLlcpDeactivated (); 310 mDefaultSnepServer.stop(); 311 mNdefPushServer.stop(); 312 mHandoverServer.stop(); 313 if (mEchoServer != null) { 314 mHandler.sendEmptyMessage(MSG_STOP_ECHOSERVER); 315 } 316 if (mExtDtaSnepServerRunning) 317 disableExtDtaSnepServer(); 318 } 319 mIsSendEnabled = sendEnable; 320 mIsReceiveEnabled = receiveEnable; 321 } 322 } 323 324 /** 325 * To Enable DTA SNEP Server for NFC Forum testing 326 */ enableExtDtaSnepServer(String serviceName, int serviceSap, int miu, int rwSize,int testCaseId)327 public void enableExtDtaSnepServer(String serviceName, int serviceSap, int miu, int rwSize,int testCaseId) { 328 if (DBG) Log.d(TAG, "Enabling Extended DTA Server"); 329 mServiceName = serviceName; 330 mServiceSap = serviceSap; 331 mDtaMiu = miu; 332 mDtaRwSize = rwSize; 333 mTestCaseID = testCaseId; 334 synchronized (this) { 335 if(mExtDtaSnepServer == null) 336 mExtDtaSnepServer = new ExtDtaSnepServer(mServiceName, mServiceSap, mDtaMiu, mDtaRwSize, 337 mExtDtaSnepServerCallback,mContext, mTestCaseID); 338 mExtDtaSnepServer.start(); 339 mExtDtaSnepServerRunning = true; 340 } 341 mServerEnabled = true; 342 } 343 344 /** 345 * To Disable DTA SNEP Server for NFC Forum testing 346 */ disableExtDtaSnepServer()347 public void disableExtDtaSnepServer() { 348 if (DBG) Log.d(TAG, "Disabling Extended DTA Server"); 349 if (!mExtDtaSnepServerRunning) 350 return; 351 synchronized (this) { 352 mExtDtaSnepServer.stop(); 353 mExtDtaSnepServer = null; 354 mExtDtaSnepServerRunning = false; 355 } 356 mServerEnabled = false; 357 } 358 359 /** 360 * To Enable DTA SNEP Client for NFC Forum testing 361 */ enableDtaSnepClient(String serviceName, int miu, int rwSize, int testCaseId)362 public void enableDtaSnepClient(String serviceName, int miu, int rwSize, int testCaseId) { 363 if (DBG) Log.d(TAG, "enableDtaSnepClient"); 364 mClientEnabled = true; 365 mServiceName = serviceName; 366 mServiceSap = -1; 367 mDtaMiu = miu; 368 mDtaRwSize = rwSize; 369 mTestCaseID = testCaseId; 370 } 371 372 /** 373 * To Disable DTA SNEP Client for NFC Forum testing 374 */ disableDtaSnepClient()375 public void disableDtaSnepClient() { 376 if (DBG) Log.d(TAG, "disableDtaSnepClient"); 377 mDtaSnepClient = null; 378 mClientEnabled = false; 379 } 380 381 382 /** 383 * May be called from any thread. 384 * @return whether the LLCP link is in an active or debounce state 385 */ isLlcpActive()386 public boolean isLlcpActive() { 387 synchronized (this) { 388 return mLinkState != LINK_STATE_DOWN; 389 } 390 } 391 392 /** 393 * Set NDEF callback for sending. 394 * May be called from any thread. 395 * NDEF callbacks may be set at any time (even if NFC is 396 * currently off or P2P send is currently off). They will become 397 * active as soon as P2P send is enabled. 398 */ setNdefCallback(IAppCallback callbackNdef, int callingUid)399 public void setNdefCallback(IAppCallback callbackNdef, int callingUid) { 400 synchronized (this) { 401 mCallbackNdef = callbackNdef; 402 mNdefCallbackUid = callingUid; 403 } 404 } 405 406 onManualBeamInvoke(BeamShareData shareData)407 public void onManualBeamInvoke(BeamShareData shareData) { 408 synchronized (P2pLinkManager.this) { 409 if (mLinkState != LINK_STATE_DOWN) { 410 return; 411 } 412 if (mForegroundUtils.getForegroundUids().contains(mNdefCallbackUid)) { 413 // Try to get data from the registered NDEF callback 414 prepareMessageToSend(false); 415 } else { 416 mMessageToSend = null; 417 mUrisToSend = null; 418 } 419 if (mMessageToSend == null && mUrisToSend == null && shareData != null) { 420 // No data from the NDEF callback, get data from ShareData 421 if (shareData.uris != null) { 422 mUrisToSend = shareData.uris; 423 } else if (shareData.ndefMessage != null) { 424 mMessageToSend = shareData.ndefMessage; 425 } 426 427 mUserHandle = shareData.userHandle; 428 } 429 if (mMessageToSend != null || 430 (mUrisToSend != null && mHandoverDataParser.isHandoverSupported())) { 431 mSendState = SEND_STATE_PENDING; 432 mEventListener.onP2pNfcTapRequested(); 433 scheduleTimeoutLocked(MSG_WAIT_FOR_LINK_TIMEOUT, WAIT_FOR_LINK_TIMEOUT_MS); 434 } 435 } 436 } 437 438 /** 439 * Must be called on UI Thread. 440 */ onLlcpActivated(byte peerLlcpVersion)441 public void onLlcpActivated(byte peerLlcpVersion) { 442 Log.i(TAG, "LLCP activated"); 443 synchronized (P2pLinkManager.this) { 444 if (mEchoServer != null) { 445 mEchoServer.onLlcpActivated(); 446 } 447 mLastLlcpActivationTime = SystemClock.elapsedRealtime(); 448 mPeerLlcpVersion = peerLlcpVersion; 449 switch (mLinkState) { 450 case LINK_STATE_DOWN: 451 if (!mEventListener.isP2pIdle() && mSendState != SEND_STATE_PENDING) { 452 break; 453 } 454 455 if (DBG) Log.d(TAG, "onP2pInRange()"); 456 // Start taking a screenshot 457 mEventListener.onP2pInRange(); 458 mLinkState = LINK_STATE_UP; 459 // If we had a pending send (manual Beam invoke), 460 // mark it as sending 461 if (mSendState == SEND_STATE_PENDING) { 462 mSendState = SEND_STATE_SENDING; 463 mHandler.removeMessages(MSG_WAIT_FOR_LINK_TIMEOUT); 464 // Immediately try to connect LLCP services 465 connectLlcpServices(); 466 } else { 467 mSendState = SEND_STATE_NOTHING_TO_SEND; 468 prepareMessageToSend(true); 469 if (mMessageToSend != null || 470 (mUrisToSend != null && mHandoverDataParser.isHandoverSupported())) { 471 // We have data to send, connect LLCP services 472 connectLlcpServices(); 473 if ((mSendFlags & NfcAdapter.FLAG_NDEF_PUSH_NO_CONFIRM) != 0) { 474 mSendState = SEND_STATE_SENDING; 475 } else { 476 mSendState = SEND_STATE_NEED_CONFIRMATION; 477 } 478 } 479 } 480 break; 481 case LINK_STATE_UP: 482 if (DBG) Log.d(TAG, "Duplicate onLlcpActivated()"); 483 return; 484 case LINK_STATE_DEBOUNCE: 485 // Immediately connect and try to send again 486 mLinkState = LINK_STATE_UP; 487 if (mSendState == SEND_STATE_SENDING || 488 mSendState == SEND_STATE_NEED_CONFIRMATION) { 489 // If we have something to send still, connect LLCP 490 connectLlcpServices(); 491 } 492 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 493 break; 494 } 495 } 496 } 497 498 /** 499 * Must be called on UI Thread. 500 */ onLlcpFirstPacketReceived()501 public void onLlcpFirstPacketReceived() { 502 synchronized (P2pLinkManager.this) { 503 long totalTime = SystemClock.elapsedRealtime() - mLastLlcpActivationTime; 504 if (DBG) Log.d(TAG, "Took " + Long.toString(totalTime) + " to get first LLCP PDU"); 505 } 506 } 507 onUserSwitched(int userId)508 public void onUserSwitched(int userId) { 509 // Update the cached package manager in case of user switch 510 synchronized (P2pLinkManager.this) { 511 try { 512 mPackageManager = mContext.createPackageContextAsUser("android", 0, 513 new UserHandle(userId)).getPackageManager(); 514 } catch (NameNotFoundException e) { 515 Log.e(TAG, "Failed to retrieve PackageManager for user"); 516 } 517 } 518 } 519 prepareMessageToSend(boolean generatePlayLink)520 void prepareMessageToSend(boolean generatePlayLink) { 521 synchronized (P2pLinkManager.this) { 522 mMessageToSend = null; 523 mUrisToSend = null; 524 if (!mIsSendEnabled) { 525 return; 526 } 527 528 List<Integer> foregroundUids = mForegroundUtils.getForegroundUids(); 529 if (foregroundUids.isEmpty()) { 530 Log.e(TAG, "Could not determine foreground UID."); 531 return; 532 } 533 534 if (isBeamDisabled(foregroundUids.get(0))) { 535 if (DBG) Log.d(TAG, "Beam is disabled by policy."); 536 return; 537 } 538 539 if (mCallbackNdef != null) { 540 if (foregroundUids.contains(mNdefCallbackUid)) { 541 try { 542 BeamShareData shareData = mCallbackNdef.createBeamShareData(mPeerLlcpVersion); 543 mMessageToSend = shareData.ndefMessage; 544 mUrisToSend = shareData.uris; 545 mUserHandle = shareData.userHandle; 546 mSendFlags = shareData.flags; 547 return; 548 } catch (Exception e) { 549 Log.e(TAG, "Failed NDEF callback: ", e); 550 } 551 } else { 552 // This is not necessarily an error - we no longer unset callbacks from 553 // the app process itself (to prevent IPC calls on every pause). 554 // Hence it may simply be a stale callback. 555 if (DBG) Log.d(TAG, "Last registered callback is not running in the foreground."); 556 } 557 } 558 559 // fall back to default NDEF for the foreground activity, unless the 560 // application disabled this explicitly in their manifest. 561 String[] pkgs = mPackageManager.getPackagesForUid(foregroundUids.get(0)); 562 if (pkgs != null && pkgs.length >= 1) { 563 if (!generatePlayLink || beamDefaultDisabled(pkgs[0])) { 564 if (DBG) Log.d(TAG, "Disabling default Beam behavior"); 565 mMessageToSend = null; 566 mUrisToSend = null; 567 } else { 568 mMessageToSend = createDefaultNdef(pkgs[0]); 569 mUrisToSend = null; 570 mSendFlags = 0; 571 } 572 } 573 574 if (DBG) Log.d(TAG, "mMessageToSend = " + mMessageToSend); 575 if (DBG) Log.d(TAG, "mUrisToSend = " + mUrisToSend); 576 } 577 } 578 isBeamDisabled(int uid)579 private boolean isBeamDisabled(int uid) { 580 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 581 UserInfo userInfo = userManager.getUserInfo(UserHandle.getUserId(uid)); 582 return userManager.hasUserRestriction( 583 UserManager.DISALLOW_OUTGOING_BEAM, userInfo.getUserHandle()); 584 585 } 586 beamDefaultDisabled(String pkgName)587 boolean beamDefaultDisabled(String pkgName) { 588 try { 589 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkgName, 590 PackageManager.GET_META_DATA); 591 if (ai == null || ai.metaData == null) { 592 return false; 593 } 594 return ai.metaData.getBoolean(DISABLE_BEAM_DEFAULT); 595 } catch (NameNotFoundException e) { 596 return false; 597 } 598 } 599 createDefaultNdef(String pkgName)600 NdefMessage createDefaultNdef(String pkgName) { 601 NdefRecord appUri = NdefRecord.createUri(Uri.parse( 602 "http://play.google.com/store/apps/details?id=" + pkgName + "&feature=beam")); 603 NdefRecord appRecord = NdefRecord.createApplicationRecord(pkgName); 604 return new NdefMessage(new NdefRecord[] { appUri, appRecord }); 605 } 606 disconnectLlcpServices()607 void disconnectLlcpServices() { 608 synchronized (this) { 609 if (mConnectTask != null) { 610 mConnectTask.cancel(true); 611 mConnectTask = null; 612 } 613 // Close any already connected LLCP clients 614 if (mNdefPushClient != null) { 615 mNdefPushClient.close(); 616 mNdefPushClient = null; 617 } 618 if (mSnepClient != null) { 619 mSnepClient.close(); 620 mSnepClient = null; 621 } 622 if (mHandoverClient != null) { 623 mHandoverClient.close(); 624 mHandoverClient = null; 625 } 626 mLlcpServicesConnected = false; 627 } 628 } 629 630 /** 631 * Must be called on UI Thread. 632 */ onLlcpDeactivated()633 public void onLlcpDeactivated() { 634 Log.i(TAG, "LLCP deactivated."); 635 synchronized (this) { 636 if (mEchoServer != null) { 637 mEchoServer.onLlcpDeactivated(); 638 } 639 640 switch (mLinkState) { 641 case LINK_STATE_DOWN: 642 case LINK_STATE_DEBOUNCE: 643 Log.i(TAG, "Duplicate onLlcpDectivated()"); 644 break; 645 case LINK_STATE_UP: 646 // Debounce 647 mLinkState = LINK_STATE_DEBOUNCE; 648 int debounceTimeout = 0; 649 switch (mSendState) { 650 case SEND_STATE_NOTHING_TO_SEND: 651 debounceTimeout = 0; 652 break; 653 case SEND_STATE_NEED_CONFIRMATION: 654 debounceTimeout = LINK_SEND_PENDING_DEBOUNCE_MS; 655 break; 656 case SEND_STATE_SENDING: 657 debounceTimeout = LINK_SEND_CONFIRMED_DEBOUNCE_MS; 658 break; 659 case SEND_STATE_COMPLETE: 660 debounceTimeout = LINK_SEND_COMPLETE_DEBOUNCE_MS; 661 break; 662 case SEND_STATE_CANCELED: 663 debounceTimeout = LINK_SEND_CANCELED_DEBOUNCE_MS; 664 } 665 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, debounceTimeout); 666 if (mSendState == SEND_STATE_SENDING) { 667 Log.e(TAG, "onP2pSendDebounce()"); 668 mEventListener.onP2pSendDebounce(); 669 } 670 cancelSendNdefMessage(); 671 disconnectLlcpServices(); 672 break; 673 } 674 } 675 } 676 onHandoverUnsupported()677 void onHandoverUnsupported() { 678 mHandler.sendEmptyMessage(MSG_HANDOVER_NOT_SUPPORTED); 679 } 680 onHandoverBusy()681 void onHandoverBusy() { 682 mHandler.sendEmptyMessage(MSG_HANDOVER_BUSY); 683 } 684 onSendComplete(NdefMessage msg, long elapsedRealtime)685 void onSendComplete(NdefMessage msg, long elapsedRealtime) { 686 // Make callbacks on UI thread 687 mHandler.sendEmptyMessage(MSG_SEND_COMPLETE); 688 } 689 sendNdefMessage()690 void sendNdefMessage() { 691 synchronized (this) { 692 cancelSendNdefMessage(); 693 mSendTask = new SendTask(); 694 mSendTask.execute(); 695 } 696 } 697 cancelSendNdefMessage()698 void cancelSendNdefMessage() { 699 synchronized (P2pLinkManager.this) { 700 if (mSendTask != null) { 701 mSendTask.cancel(true); 702 } 703 } 704 } 705 connectLlcpServices()706 void connectLlcpServices() { 707 synchronized (P2pLinkManager.this) { 708 if (mConnectTask != null) { 709 Log.e(TAG, "Still had a reference to mConnectTask!"); 710 } 711 mConnectTask = new ConnectTask(); 712 mConnectTask.execute(); 713 } 714 } 715 716 // Must be called on UI-thread onLlcpServicesConnected()717 void onLlcpServicesConnected() { 718 if (DBG) Log.d(TAG, "onLlcpServicesConnected"); 719 synchronized (P2pLinkManager.this) { 720 if (mLinkState != LINK_STATE_UP) { 721 return; 722 } 723 mLlcpServicesConnected = true; 724 if (mSendState == SEND_STATE_NEED_CONFIRMATION) { 725 if (DBG) Log.d(TAG, "onP2pSendConfirmationRequested()"); 726 mEventListener.onP2pSendConfirmationRequested(); 727 } else if (mSendState == SEND_STATE_SENDING) { 728 mEventListener.onP2pResumeSend(); 729 sendNdefMessage(); 730 } else { 731 // Either nothing to send or canceled/complete, ignore 732 } 733 } 734 } 735 736 final class ConnectTask extends AsyncTask<Void, Void, Boolean> { 737 @Override onPostExecute(Boolean result)738 protected void onPostExecute(Boolean result) { 739 if (isCancelled()) { 740 if (DBG) Log.d(TAG, "ConnectTask was cancelled"); 741 return; 742 } 743 if (result) { 744 onLlcpServicesConnected(); 745 } else { 746 Log.e(TAG, "Could not connect required NFC transports"); 747 } 748 } 749 750 @Override doInBackground(Void... params)751 protected Boolean doInBackground(Void... params) { 752 boolean needsHandover = false; 753 boolean needsNdef = false; 754 boolean success = false; 755 HandoverClient handoverClient = null; 756 SnepClient snepClient = null; 757 NdefPushClient nppClient = null; 758 759 synchronized(P2pLinkManager.this) { 760 if (mUrisToSend != null) { 761 needsHandover = true; 762 } 763 764 if (mMessageToSend != null) { 765 needsNdef = true; 766 } 767 } 768 // We know either is requested - otherwise this task 769 // wouldn't have been started. 770 if (needsHandover) { 771 handoverClient = new HandoverClient(); 772 try { 773 handoverClient.connect(); 774 success = true; // Regardless of NDEF result 775 } catch (IOException e) { 776 handoverClient = null; 777 } 778 } 779 if (needsNdef || (needsHandover && handoverClient == null)) { 780 if (NfcService.sIsDtaMode) { 781 if (mClientEnabled) { 782 if (mDtaSnepClient == null) { 783 if (DBG) Log.d(TAG, "Creating DTA Snep Client"); 784 mDtaSnepClient = new DtaSnepClient(mServiceName, mDtaMiu, mDtaRwSize, mTestCaseID); 785 } 786 } 787 } else 788 snepClient = new SnepClient(); 789 try { 790 if (NfcService.sIsDtaMode) { 791 if (mDtaSnepClient != null) 792 mDtaSnepClient.DtaClientOperations(mContext); 793 } 794 else 795 snepClient.connect(); 796 success = true; 797 mDtaSnepClient = null; 798 } catch (IOException e) { 799 snepClient = null; 800 } 801 802 if (!success) { 803 nppClient = new NdefPushClient(); 804 try { 805 nppClient.connect(); 806 success = true; 807 } catch (IOException e) { 808 nppClient = null; 809 } 810 } 811 } 812 813 synchronized (P2pLinkManager.this) { 814 if (isCancelled()) { 815 // Cancelled by onLlcpDeactivated on UI thread 816 if (handoverClient != null) { 817 handoverClient.close(); 818 } 819 if (snepClient != null) { 820 snepClient.close(); 821 } 822 if (nppClient != null) { 823 nppClient.close(); 824 } 825 if (mDtaSnepClient != null) { 826 mDtaSnepClient.close(); 827 } 828 return false; 829 } else { 830 // Once assigned, these are the responsibility of 831 // the code on the UI thread to release - typically 832 // through onLlcpDeactivated(). 833 mHandoverClient = handoverClient; 834 mSnepClient = snepClient; 835 mNdefPushClient = nppClient; 836 return success; 837 } 838 } 839 } 840 }; 841 842 final class SendTask extends AsyncTask<Void, Void, Void> { 843 NdefPushClient nppClient; 844 SnepClient snepClient; 845 HandoverClient handoverClient; 846 doHandover(Uri[] uris, UserHandle userHandle)847 int doHandover(Uri[] uris, UserHandle userHandle) throws IOException { 848 NdefMessage response = null; 849 BeamManager beamManager = BeamManager.getInstance(); 850 851 if (beamManager.isBeamInProgress()) { 852 return HANDOVER_BUSY; 853 } 854 855 NdefMessage request = mHandoverDataParser.createHandoverRequestMessage(); 856 if (request != null) { 857 if (handoverClient != null) { 858 response = handoverClient.sendHandoverRequest(request); 859 } 860 if (response == null && snepClient != null) { 861 // Remote device may not support handover service, 862 // try the (deprecated) SNEP GET implementation 863 // for devices running Android 4.1 864 SnepMessage snepResponse = snepClient.get(request); 865 response = snepResponse.getNdefMessage(); 866 } 867 if (response == null) { 868 if (snepClient != null) 869 return HANDOVER_UNSUPPORTED; 870 else 871 return HANDOVER_FAILURE; 872 } 873 } else { 874 return HANDOVER_UNSUPPORTED; 875 } 876 877 if (!beamManager.startBeamSend(mContext, 878 mHandoverDataParser.getOutgoingHandoverData(response), uris, userHandle)) { 879 return HANDOVER_BUSY; 880 } 881 882 return HANDOVER_SUCCESS; 883 } 884 doSnepProtocol(NdefMessage msg)885 int doSnepProtocol(NdefMessage msg) throws IOException { 886 if (msg != null) { 887 snepClient.put(msg); 888 return SNEP_SUCCESS; 889 } else { 890 return SNEP_FAILURE; 891 } 892 } 893 894 @Override doInBackground(Void... args)895 public Void doInBackground(Void... args) { 896 NdefMessage m; 897 Uri[] uris; 898 UserHandle userHandle; 899 boolean result = false; 900 901 synchronized (P2pLinkManager.this) { 902 if (mLinkState != LINK_STATE_UP || mSendState != SEND_STATE_SENDING) { 903 return null; 904 } 905 m = mMessageToSend; 906 uris = mUrisToSend; 907 userHandle = mUserHandle; 908 snepClient = mSnepClient; 909 handoverClient = mHandoverClient; 910 nppClient = mNdefPushClient; 911 } 912 913 long time = SystemClock.elapsedRealtime(); 914 915 if (uris != null) { 916 if (DBG) Log.d(TAG, "Trying handover request"); 917 try { 918 int handoverResult = doHandover(uris, userHandle); 919 switch (handoverResult) { 920 case HANDOVER_SUCCESS: 921 result = true; 922 break; 923 case HANDOVER_FAILURE: 924 result = false; 925 break; 926 case HANDOVER_UNSUPPORTED: 927 result = false; 928 onHandoverUnsupported(); 929 break; 930 case HANDOVER_BUSY: 931 result = false; 932 onHandoverBusy(); 933 break; 934 } 935 } catch (IOException e) { 936 result = false; 937 } 938 } 939 940 if (!result && m != null && snepClient != null) { 941 if (DBG) Log.d(TAG, "Sending ndef via SNEP"); 942 try { 943 int snepResult = doSnepProtocol(m); 944 switch (snepResult) { 945 case SNEP_SUCCESS: 946 result = true; 947 break; 948 case SNEP_FAILURE: 949 result = false; 950 break; 951 default: 952 result = false; 953 } 954 } catch (IOException e) { 955 result = false; 956 } 957 } 958 959 if (!result && m != null && nppClient != null) { 960 result = nppClient.push(m); 961 } 962 963 time = SystemClock.elapsedRealtime() - time; 964 if (DBG) Log.d(TAG, "SendTask result=" + result + ", time ms=" + time); 965 if (result) { 966 onSendComplete(m, time); 967 } 968 969 return null; 970 } 971 }; 972 973 974 final HandoverServer.Callback mHandoverCallback = new HandoverServer.Callback() { 975 @Override 976 public void onHandoverRequestReceived() { 977 onReceiveHandover(); 978 } 979 980 @Override 981 public void onHandoverBusy() { 982 P2pLinkManager.this.onHandoverBusy(); 983 } 984 }; 985 986 final NdefPushServer.Callback mNppCallback = new NdefPushServer.Callback() { 987 @Override 988 public void onMessageReceived(NdefMessage msg) { 989 onReceiveComplete(msg); 990 } 991 }; 992 993 final SnepServer.Callback mDefaultSnepCallback = new SnepServer.Callback() { 994 @Override 995 public SnepMessage doPut(NdefMessage msg) { 996 if(NfcService.sIsDtaMode) 997 Log.d(TAG, "DTA mode enabled, dont dispatch the tag"); 998 else 999 onReceiveComplete(msg); 1000 return SnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS); 1001 } 1002 1003 @Override 1004 public SnepMessage doGet(int acceptableLength, NdefMessage msg) { 1005 // The NFC Forum Default SNEP server is not allowed to respond to 1006 // SNEP GET requests - see SNEP 1.0 TS section 6.1. However, 1007 // since Android 4.1 used the NFC Forum default server to 1008 // implement connection handover, we will support this 1009 // until we can deprecate it. 1010 NdefMessage response = null; 1011 if (NfcService.sIsDtaMode){ 1012 if(msg != null && mHandoverDataParser.getIncomingHandoverData(msg) != null) { 1013 response = mHandoverDataParser.getIncomingHandoverData(msg).handoverSelect; 1014 } 1015 } else { 1016 response = mHandoverDataParser.getIncomingHandoverData(msg).handoverSelect; 1017 } 1018 if (response != null) { 1019 onReceiveHandover(); 1020 return SnepMessage.getSuccessResponse(response); 1021 } else { 1022 return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED); 1023 } 1024 } 1025 }; 1026 final ExtDtaSnepServer.Callback mExtDtaSnepServerCallback = new ExtDtaSnepServer.Callback() { 1027 @Override 1028 public SnepMessage doPut(NdefMessage msg) { 1029 mPutBeforeGet = true; 1030 return SnepMessage.getMessage(SnepMessage.RESPONSE_SUCCESS); 1031 } 1032 1033 @Override 1034 public SnepMessage doGet(int acceptableLength, NdefMessage msg) { 1035 if ((!mPutBeforeGet)) { 1036 return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_FOUND); 1037 } else if (acceptableLength == 501) { 1038 mPutBeforeGet = false; 1039 return SnepMessage.getMessage(SnepMessage.RESPONSE_EXCESS_DATA); 1040 } else if (mPutBeforeGet&&(acceptableLength == 1024)) { 1041 try { 1042 mPutBeforeGet = false; 1043 return SnepMessage.getSuccessResponse(SnepMessage.getLargeNdef()); 1044 } catch (UnsupportedEncodingException e) { 1045 mPutBeforeGet = false; 1046 return null; 1047 } 1048 } else { 1049 mPutBeforeGet = false; 1050 return SnepMessage.getMessage(SnepMessage.RESPONSE_NOT_IMPLEMENTED); 1051 } 1052 } 1053 }; 1054 onReceiveHandover()1055 void onReceiveHandover() { 1056 mHandler.obtainMessage(MSG_RECEIVE_HANDOVER).sendToTarget(); 1057 } 1058 onReceiveComplete(NdefMessage msg)1059 void onReceiveComplete(NdefMessage msg) { 1060 // Make callbacks on UI thread 1061 mHandler.obtainMessage(MSG_RECEIVE_COMPLETE, msg).sendToTarget(); 1062 } 1063 1064 @Override handleMessage(Message msg)1065 public boolean handleMessage(Message msg) { 1066 switch (msg.what) { 1067 case MSG_START_ECHOSERVER: 1068 synchronized (this) { 1069 mEchoServer.start(); 1070 break; 1071 } 1072 case MSG_STOP_ECHOSERVER: 1073 synchronized (this) { 1074 mEchoServer.stop(); 1075 break; 1076 } 1077 case MSG_WAIT_FOR_LINK_TIMEOUT: 1078 synchronized (this) { 1079 // User wanted to send something but no link 1080 // came up. Just cancel the send 1081 mSendState = SEND_STATE_NOTHING_TO_SEND; 1082 mEventListener.onP2pTimeoutWaitingForLink(); 1083 } 1084 break; 1085 case MSG_DEBOUNCE_TIMEOUT: 1086 synchronized (this) { 1087 if (mLinkState != LINK_STATE_DEBOUNCE) { 1088 break; 1089 } 1090 if (DBG) Log.d(TAG, "Debounce timeout"); 1091 mLinkState = LINK_STATE_DOWN; 1092 mSendState = SEND_STATE_NOTHING_TO_SEND; 1093 mMessageToSend = null; 1094 mUrisToSend = null; 1095 if (DBG) Log.d(TAG, "onP2pOutOfRange()"); 1096 mEventListener.onP2pOutOfRange(); 1097 } 1098 break; 1099 case MSG_RECEIVE_HANDOVER: 1100 // We're going to do a handover request 1101 synchronized (this) { 1102 if (mLinkState == LINK_STATE_DOWN) { 1103 break; 1104 } 1105 if (mSendState == SEND_STATE_SENDING) { 1106 cancelSendNdefMessage(); 1107 } 1108 mSendState = SEND_STATE_NOTHING_TO_SEND; 1109 if (DBG) Log.d(TAG, "onP2pReceiveComplete()"); 1110 mEventListener.onP2pReceiveComplete(false); 1111 StatsLog.write(StatsLog.NFC_BEAM_OCCURRED, StatsLog.NFC_BEAM_OCCURRED__OPERATION__RECEIVE); 1112 } 1113 break; 1114 case MSG_RECEIVE_COMPLETE: 1115 NdefMessage m = (NdefMessage) msg.obj; 1116 synchronized (this) { 1117 if (mLinkState == LINK_STATE_DOWN) { 1118 break; 1119 } 1120 if (mSendState == SEND_STATE_SENDING) { 1121 cancelSendNdefMessage(); 1122 } 1123 mSendState = SEND_STATE_NOTHING_TO_SEND; 1124 if (DBG) Log.d(TAG, "onP2pReceiveComplete()"); 1125 mEventListener.onP2pReceiveComplete(true); 1126 NfcService.getInstance().sendMockNdefTag(m); 1127 StatsLog.write(StatsLog.NFC_BEAM_OCCURRED, StatsLog.NFC_BEAM_OCCURRED__OPERATION__RECEIVE); 1128 } 1129 break; 1130 case MSG_HANDOVER_NOT_SUPPORTED: 1131 synchronized (P2pLinkManager.this) { 1132 mSendTask = null; 1133 1134 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 1135 break; 1136 } 1137 mSendState = SEND_STATE_NOTHING_TO_SEND; 1138 if (DBG) Log.d(TAG, "onP2pHandoverNotSupported()"); 1139 mEventListener.onP2pHandoverNotSupported(); 1140 } 1141 break; 1142 case MSG_SEND_COMPLETE: 1143 synchronized (P2pLinkManager.this) { 1144 mSendTask = null; 1145 1146 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 1147 break; 1148 } 1149 mSendState = SEND_STATE_COMPLETE; 1150 mHandler.removeMessages(MSG_DEBOUNCE_TIMEOUT); 1151 if (DBG) Log.d(TAG, "onP2pSendComplete()"); 1152 mEventListener.onP2pSendComplete(); 1153 if (mCallbackNdef != null) { 1154 try { 1155 mCallbackNdef.onNdefPushComplete(mPeerLlcpVersion); 1156 } catch (Exception e) { 1157 Log.e(TAG, "Failed NDEF completed callback: " + e.getMessage()); 1158 } 1159 } 1160 StatsLog.write(StatsLog.NFC_BEAM_OCCURRED, StatsLog.NFC_BEAM_OCCURRED__OPERATION__SEND); 1161 } 1162 break; 1163 case MSG_HANDOVER_BUSY: 1164 synchronized (P2pLinkManager.this) { 1165 mSendTask = null; 1166 1167 if (mLinkState == LINK_STATE_DOWN || mSendState != SEND_STATE_SENDING) { 1168 break; 1169 } 1170 mSendState = SEND_STATE_NOTHING_TO_SEND; 1171 if (DBG) Log.d(TAG, "onP2pHandoverBusy()"); 1172 mEventListener.onP2pHandoverBusy(); 1173 } 1174 } 1175 return true; 1176 } 1177 1178 1179 @Override onP2pSendConfirmed()1180 public void onP2pSendConfirmed() { 1181 onP2pSendConfirmed(true); 1182 } 1183 onP2pSendConfirmed(boolean requireConfirmation)1184 private void onP2pSendConfirmed(boolean requireConfirmation) { 1185 if (DBG) Log.d(TAG, "onP2pSendConfirmed()"); 1186 synchronized (this) { 1187 if (mLinkState == LINK_STATE_DOWN || (requireConfirmation 1188 && mSendState != SEND_STATE_NEED_CONFIRMATION)) { 1189 return; 1190 } 1191 mSendState = SEND_STATE_SENDING; 1192 if (mLinkState == LINK_STATE_UP) { 1193 if (mLlcpServicesConnected) { 1194 sendNdefMessage(); 1195 } // else, will send messages when link comes up 1196 } else if (mLinkState == LINK_STATE_DEBOUNCE) { 1197 // Restart debounce timeout and tell user to tap again 1198 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, LINK_SEND_CONFIRMED_DEBOUNCE_MS); 1199 mEventListener.onP2pSendDebounce(); 1200 } 1201 } 1202 } 1203 1204 1205 @Override onP2pCanceled()1206 public void onP2pCanceled() { 1207 synchronized (this) { 1208 mSendState = SEND_STATE_CANCELED; 1209 if (mLinkState == LINK_STATE_DOWN) { 1210 // If we were waiting for the link to come up, stop doing so 1211 mHandler.removeMessages(MSG_WAIT_FOR_LINK_TIMEOUT); 1212 } else if (mLinkState == LINK_STATE_DEBOUNCE) { 1213 // We're in debounce state so link is down. Reschedule debounce 1214 // timeout to occur sooner, we don't want to wait any longer. 1215 scheduleTimeoutLocked(MSG_DEBOUNCE_TIMEOUT, LINK_SEND_CANCELED_DEBOUNCE_MS); 1216 } else { 1217 // Link is up, nothing else to do but wait for link to go down 1218 } 1219 } 1220 } 1221 scheduleTimeoutLocked(int what, int timeout)1222 void scheduleTimeoutLocked(int what, int timeout) { 1223 // Cancel any outstanding debounce timeouts. 1224 mHandler.removeMessages(what); 1225 mHandler.sendEmptyMessageDelayed(what, timeout); 1226 } 1227 sendStateToString(int state)1228 static String sendStateToString(int state) { 1229 switch (state) { 1230 case SEND_STATE_NOTHING_TO_SEND: 1231 return "SEND_STATE_NOTHING_TO_SEND"; 1232 case SEND_STATE_NEED_CONFIRMATION: 1233 return "SEND_STATE_NEED_CONFIRMATION"; 1234 case SEND_STATE_SENDING: 1235 return "SEND_STATE_SENDING"; 1236 case SEND_STATE_COMPLETE: 1237 return "SEND_STATE_COMPLETE"; 1238 case SEND_STATE_CANCELED: 1239 return "SEND_STATE_CANCELED"; 1240 default: 1241 return "<error>"; 1242 } 1243 } 1244 linkStateToString(int state)1245 static String linkStateToString(int state) { 1246 switch (state) { 1247 case LINK_STATE_DOWN: 1248 return "LINK_STATE_DOWN"; 1249 case LINK_STATE_DEBOUNCE: 1250 return "LINK_STATE_DEBOUNCE"; 1251 case LINK_STATE_UP: 1252 return "LINK_STATE_UP"; 1253 default: 1254 return "<error>"; 1255 } 1256 } 1257 dump(FileDescriptor fd, PrintWriter pw, String[] args)1258 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1259 synchronized (this) { 1260 pw.println("mIsSendEnabled=" + mIsSendEnabled); 1261 pw.println("mIsReceiveEnabled=" + mIsReceiveEnabled); 1262 pw.println("mLinkState=" + linkStateToString(mLinkState)); 1263 pw.println("mSendState=" + sendStateToString(mSendState)); 1264 1265 pw.println("mCallbackNdef=" + mCallbackNdef); 1266 pw.println("mMessageToSend=" + mMessageToSend); 1267 pw.println("mUrisToSend=" + mUrisToSend); 1268 } 1269 } 1270 } 1271