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