• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 #include <android-base/stringprintf.h>
18 #include <base/logging.h>
19 #include <errno.h>
20 #include <malloc.h>
21 #include <nativehelper/ScopedLocalRef.h>
22 #include <nativehelper/ScopedPrimitiveArray.h>
23 #include <semaphore.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <time.h>
27 
28 #include "IntervalTimer.h"
29 #include "JavaClassConstants.h"
30 #include "Mutex.h"
31 #include "NfcJniUtil.h"
32 #include "NfcTag.h"
33 #include "ndef_utils.h"
34 #include "nfa_api.h"
35 #include "nfa_rw_api.h"
36 #include "nfc_brcm_defs.h"
37 #include "rw_api.h"
38 
39 using android::base::StringPrintf;
40 
41 namespace android {
42 extern nfc_jni_native_data* getNative(JNIEnv* e, jobject o);
43 extern bool nfcManager_isNfcActive();
44 }  // namespace android
45 
46 extern bool gActivated;
47 extern SyncEvent gDeactivatedEvent;
48 extern bool nfc_debug_enabled;
49 
50 /*****************************************************************************
51 **
52 ** public variables and functions
53 **
54 *****************************************************************************/
55 namespace android {
56 bool gIsTagDeactivating = false;  // flag for nfa callback indicating we are
57                                   // deactivating for RF interface switch
58 bool gIsSelectingRfInterface =
59     false;  // flag for nfa callback indicating we are
60             // selecting for RF interface switch
61 }  // namespace android
62 
63 /*****************************************************************************
64 **
65 ** private variables and functions
66 **
67 *****************************************************************************/
68 namespace android {
69 
70 // Pre-defined tag type values. These must match the values in
71 // framework Ndef.java for Google public NFC API.
72 #define NDEF_UNKNOWN_TYPE (-1)
73 #define NDEF_TYPE1_TAG 1
74 #define NDEF_TYPE2_TAG 2
75 #define NDEF_TYPE3_TAG 3
76 #define NDEF_TYPE4_TAG 4
77 #define NDEF_MIFARE_CLASSIC_TAG 101
78 
79 #define STATUS_CODE_TARGET_LOST 146  // this error code comes from the service
80 
81 static uint32_t sCheckNdefCurrentSize = 0;
82 static tNFA_STATUS sCheckNdefStatus =
83     0;  // whether tag already contains a NDEF message
84 static bool sCheckNdefCapable = false;  // whether tag has NDEF capability
85 static tNFA_HANDLE sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
86 static tNFA_INTF_TYPE sCurrentRfInterface = NFA_INTERFACE_ISO_DEP;
87 static tNFA_INTF_TYPE sCurrentActivatedProtocl = NFA_INTERFACE_ISO_DEP;
88 static std::basic_string<uint8_t> sRxDataBuffer;
89 static tNFA_STATUS sRxDataStatus = NFA_STATUS_OK;
90 static bool sWaitingForTransceive = false;
91 static bool sTransceiveRfTimeout = false;
92 static Mutex sRfInterfaceMutex;
93 static uint32_t sReadDataLen = 0;
94 static uint8_t* sReadData = NULL;
95 static bool sIsReadingNdefMessage = false;
96 static SyncEvent sReadEvent;
97 static sem_t sWriteSem;
98 static sem_t sFormatSem;
99 static SyncEvent sTransceiveEvent;
100 static SyncEvent sReconnectEvent;
101 static sem_t sCheckNdefSem;
102 static SyncEvent sPresenceCheckEvent;
103 static sem_t sMakeReadonlySem;
104 static IntervalTimer sSwitchBackTimer;  // timer used to tell us to switch back
105                                         // to ISO_DEP frame interface
106 uint8_t RW_TAG_SLP_REQ[] = {0x50, 0x00};
107 uint8_t RW_DESELECT_REQ[] = {0xC2};
108 static jboolean sWriteOk = JNI_FALSE;
109 static jboolean sWriteWaitingForComplete = JNI_FALSE;
110 static bool sFormatOk = false;
111 static jboolean sConnectOk = JNI_FALSE;
112 static jboolean sConnectWaitingForComplete = JNI_FALSE;
113 static bool sGotDeactivate = false;
114 static uint32_t sCheckNdefMaxSize = 0;
115 static bool sCheckNdefCardReadOnly = false;
116 static jboolean sCheckNdefWaitingForComplete = JNI_FALSE;
117 static bool sIsTagPresent = true;
118 static tNFA_STATUS sMakeReadonlyStatus = NFA_STATUS_FAILED;
119 static jboolean sMakeReadonlyWaitingForComplete = JNI_FALSE;
120 static int sCurrentConnectedTargetType = TARGET_TYPE_UNKNOWN;
121 static int sCurrentConnectedTargetProtocol = NFC_PROTOCOL_UNKNOWN;
122 static int sCurrentConnectedHandle = 0;
123 static int sIsoDepPresCheckCnt = 0;
124 static bool sIsoDepPresCheckAlternate = false;
125 static int sPresCheckErrCnt = 0;
126 
127 static int sPresCheckStatus = 0;
128 static int reSelect(tNFA_INTF_TYPE rfInterface, bool fSwitchIfNeeded);
129 static bool switchRfInterface(tNFA_INTF_TYPE rfInterface);
130 
131 /*******************************************************************************
132 **
133 ** Function:        nativeNfcTag_abortWaits
134 **
135 ** Description:     Unblock all thread synchronization objects.
136 **
137 ** Returns:         None
138 **
139 *******************************************************************************/
nativeNfcTag_abortWaits()140 void nativeNfcTag_abortWaits() {
141   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
142   {
143     SyncEventGuard g(sReadEvent);
144     sReadEvent.notifyOne();
145   }
146   sem_post(&sWriteSem);
147   sem_post(&sFormatSem);
148   {
149     SyncEventGuard g(sTransceiveEvent);
150     sTransceiveEvent.notifyOne();
151   }
152   {
153     SyncEventGuard g(sReconnectEvent);
154     sReconnectEvent.notifyOne();
155   }
156 
157   sem_post(&sCheckNdefSem);
158   {
159     SyncEventGuard guard(sPresenceCheckEvent);
160     sPresenceCheckEvent.notifyOne();
161   }
162   sem_post(&sMakeReadonlySem);
163   sCurrentRfInterface = NFA_INTERFACE_ISO_DEP;
164   sCurrentActivatedProtocl = NFA_INTERFACE_ISO_DEP;
165   sCurrentConnectedTargetType = TARGET_TYPE_UNKNOWN;
166   sCurrentConnectedTargetProtocol = NFC_PROTOCOL_UNKNOWN;
167 
168   sIsoDepPresCheckCnt = 0;
169   sPresCheckErrCnt = 0;
170   sIsoDepPresCheckAlternate = false;
171 }
172 
173 /*******************************************************************************
174 **
175 ** Function:        nativeNfcTag_doReadCompleted
176 **
177 ** Description:     Receive the completion status of read operation.  Called by
178 **                  NFA_READ_CPLT_EVT.
179 **                  status: Status of operation.
180 **
181 ** Returns:         None
182 **
183 *******************************************************************************/
nativeNfcTag_doReadCompleted(tNFA_STATUS status)184 void nativeNfcTag_doReadCompleted(tNFA_STATUS status) {
185   DLOG_IF(INFO, nfc_debug_enabled)
186       << StringPrintf("%s: status=0x%X; is reading=%u", __func__, status,
187                       sIsReadingNdefMessage);
188 
189   if (sIsReadingNdefMessage == false)
190     return;  // not reading NDEF message right now, so just return
191 
192   if (status != NFA_STATUS_OK) {
193     sReadDataLen = 0;
194     if (sReadData) free(sReadData);
195     sReadData = NULL;
196   }
197   SyncEventGuard g(sReadEvent);
198   sReadEvent.notifyOne();
199 }
200 
201 /*******************************************************************************
202 **
203 ** Function:        nativeNfcTag_setRfInterface
204 **
205 ** Description:     Set rf interface.
206 **
207 ** Returns:         void
208 **
209 *******************************************************************************/
nativeNfcTag_setRfInterface(tNFA_INTF_TYPE rfInterface)210 void nativeNfcTag_setRfInterface(tNFA_INTF_TYPE rfInterface) {
211   sCurrentRfInterface = rfInterface;
212 }
213 
214 /*******************************************************************************
215  **
216  ** Function:        nativeNfcTag_setActivatedRfProtocol
217  **
218  ** Description:     Set rf Activated Protocol.
219  **
220  ** Returns:         void
221  **
222  *******************************************************************************/
nativeNfcTag_setActivatedRfProtocol(tNFA_INTF_TYPE rfProtocol)223 void nativeNfcTag_setActivatedRfProtocol(tNFA_INTF_TYPE rfProtocol) {
224   sCurrentActivatedProtocl = rfProtocol;
225 }
226 
227 /*******************************************************************************
228 **
229 ** Function:        ndefHandlerCallback
230 **
231 ** Description:     Receive NDEF-message related events from stack.
232 **                  event: Event code.
233 **                  p_data: Event data.
234 **
235 ** Returns:         None
236 **
237 *******************************************************************************/
ndefHandlerCallback(tNFA_NDEF_EVT event,tNFA_NDEF_EVT_DATA * eventData)238 static void ndefHandlerCallback(tNFA_NDEF_EVT event,
239                                 tNFA_NDEF_EVT_DATA* eventData) {
240   DLOG_IF(INFO, nfc_debug_enabled)
241       << StringPrintf("%s: event=%u, eventData=%p", __func__, event, eventData);
242 
243   switch (event) {
244     case NFA_NDEF_REGISTER_EVT: {
245       tNFA_NDEF_REGISTER& ndef_reg = eventData->ndef_reg;
246       DLOG_IF(INFO, nfc_debug_enabled)
247           << StringPrintf("%s: NFA_NDEF_REGISTER_EVT; status=0x%X; h=0x%X",
248                           __func__, ndef_reg.status, ndef_reg.ndef_type_handle);
249       sNdefTypeHandlerHandle = ndef_reg.ndef_type_handle;
250     } break;
251 
252     case NFA_NDEF_DATA_EVT: {
253       DLOG_IF(INFO, nfc_debug_enabled)
254           << StringPrintf("%s: NFA_NDEF_DATA_EVT; data_len = %u", __func__,
255                           eventData->ndef_data.len);
256       sReadDataLen = eventData->ndef_data.len;
257       sReadData = (uint8_t*)malloc(sReadDataLen);
258       memcpy(sReadData, eventData->ndef_data.p_data, eventData->ndef_data.len);
259     } break;
260 
261     default:
262       LOG(ERROR) << StringPrintf("%s: Unknown event %u ????", __func__, event);
263       break;
264   }
265 }
266 
267 /*******************************************************************************
268 **
269 ** Function:        nativeNfcTag_doRead
270 **
271 ** Description:     Read the NDEF message on the tag.
272 **                  e: JVM environment.
273 **                  o: Java object.
274 **
275 ** Returns:         NDEF message.
276 **
277 *******************************************************************************/
nativeNfcTag_doRead(JNIEnv * e,jobject)278 static jbyteArray nativeNfcTag_doRead(JNIEnv* e, jobject) {
279   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
280   tNFA_STATUS status = NFA_STATUS_FAILED;
281   jbyteArray buf = NULL;
282 
283   sReadDataLen = 0;
284   if (sReadData != NULL) {
285     free(sReadData);
286     sReadData = NULL;
287   }
288 
289   if (sCheckNdefCurrentSize > 0) {
290     {
291       SyncEventGuard g(sReadEvent);
292       sIsReadingNdefMessage = true;
293       status = NFA_RwReadNDef();
294       sReadEvent.wait();  // wait for NFA_READ_CPLT_EVT
295     }
296     sIsReadingNdefMessage = false;
297 
298     if (sReadDataLen > 0)  // if stack actually read data from the tag
299     {
300       DLOG_IF(INFO, nfc_debug_enabled)
301           << StringPrintf("%s: read %u bytes", __func__, sReadDataLen);
302       buf = e->NewByteArray(sReadDataLen);
303       e->SetByteArrayRegion(buf, 0, sReadDataLen, (jbyte*)sReadData);
304     }
305   } else {
306     DLOG_IF(INFO, nfc_debug_enabled)
307         << StringPrintf("%s: create empty buffer", __func__);
308     sReadDataLen = 0;
309     sReadData = (uint8_t*)malloc(1);
310     buf = e->NewByteArray(sReadDataLen);
311     e->SetByteArrayRegion(buf, 0, sReadDataLen, (jbyte*)sReadData);
312   }
313 
314   if (sReadData) {
315     free(sReadData);
316     sReadData = NULL;
317   }
318   sReadDataLen = 0;
319 
320   DLOG_IF(INFO, nfc_debug_enabled)
321       << StringPrintf("%s: exit: Status = 0x%X", __func__, status);
322   return buf;
323 }
324 
325 /*******************************************************************************
326 **
327 ** Function:        nativeNfcTag_doWriteStatus
328 **
329 ** Description:     Receive the completion status of write operation.  Called
330 **                  by NFA_WRITE_CPLT_EVT.
331 **                  isWriteOk: Status of operation.
332 **
333 ** Returns:         None
334 **
335 *******************************************************************************/
nativeNfcTag_doWriteStatus(jboolean isWriteOk)336 void nativeNfcTag_doWriteStatus(jboolean isWriteOk) {
337   if (sWriteWaitingForComplete != JNI_FALSE) {
338     sWriteWaitingForComplete = JNI_FALSE;
339     sWriteOk = isWriteOk;
340     sem_post(&sWriteSem);
341   }
342 }
343 
344 /*******************************************************************************
345 **
346 ** Function:        nativeNfcTag_formatStatus
347 **
348 ** Description:     Receive the completion status of format operation.  Called
349 **                  by NFA_FORMAT_CPLT_EVT.
350 **                  isOk: Status of operation.
351 **
352 ** Returns:         None
353 **
354 *******************************************************************************/
nativeNfcTag_formatStatus(bool isOk)355 void nativeNfcTag_formatStatus(bool isOk) {
356   sFormatOk = isOk;
357   sem_post(&sFormatSem);
358 }
359 
360 /*******************************************************************************
361 **
362 ** Function:        nativeNfcTag_doWrite
363 **
364 ** Description:     Write a NDEF message to the tag.
365 **                  e: JVM environment.
366 **                  o: Java object.
367 **                  buf: Contains a NDEF message.
368 **
369 ** Returns:         True if ok.
370 **
371 *******************************************************************************/
nativeNfcTag_doWrite(JNIEnv * e,jobject,jbyteArray buf)372 static jboolean nativeNfcTag_doWrite(JNIEnv* e, jobject, jbyteArray buf) {
373   jboolean result = JNI_FALSE;
374   tNFA_STATUS status = 0;
375   const int maxBufferSize = 1024;
376   uint8_t buffer[maxBufferSize] = {0};
377   uint32_t curDataSize = 0;
378 
379   ScopedByteArrayRO bytes(e, buf);
380   uint8_t* p_data = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(
381       &bytes[0]));  // TODO: const-ness API bug in NFA_RwWriteNDef!
382 
383   DLOG_IF(INFO, nfc_debug_enabled)
384       << StringPrintf("%s: enter; len = %zu", __func__, bytes.size());
385 
386   /* Create the write semaphore */
387   if (sem_init(&sWriteSem, 0, 0) == -1) {
388     LOG(ERROR) << StringPrintf("%s: semaphore creation failed (errno=0x%08x)",
389                                __func__, errno);
390     return JNI_FALSE;
391   }
392 
393   sWriteWaitingForComplete = JNI_TRUE;
394   if (sCheckNdefStatus == NFA_STATUS_FAILED) {
395     // if tag does not contain a NDEF message
396     // and tag is capable of storing NDEF message
397     if (sCheckNdefCapable) {
398       DLOG_IF(INFO, nfc_debug_enabled)
399           << StringPrintf("%s: try format", __func__);
400       if (0 != sem_init(&sFormatSem, 0, 0)) {
401         LOG(ERROR) << StringPrintf(
402             "%s: semaphore creation failed (errno=0x%08x)", __func__, errno);
403         return JNI_FALSE;
404       }
405       sFormatOk = false;
406       status = NFA_RwFormatTag();
407       if (status != NFA_STATUS_OK) {
408         LOG(ERROR) << StringPrintf("%s: can't format mifare classic tag",
409                                    __func__);
410         sem_destroy(&sFormatSem);
411         goto TheEnd;
412       }
413       sem_wait(&sFormatSem);
414       sem_destroy(&sFormatSem);
415       if (sFormatOk == false)  // if format operation failed
416         goto TheEnd;
417     }
418     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: try write", __func__);
419     status = NFA_RwWriteNDef(p_data, bytes.size());
420   } else if (bytes.size() == 0) {
421     // if (NXP TagWriter wants to erase tag) then create and write an empty ndef
422     // message
423     NDEF_MsgInit(buffer, maxBufferSize, &curDataSize);
424     status = NDEF_MsgAddRec(buffer, maxBufferSize, &curDataSize, NDEF_TNF_EMPTY,
425                             NULL, 0, NULL, 0, NULL, 0);
426     DLOG_IF(INFO, nfc_debug_enabled)
427         << StringPrintf("%s: create empty ndef msg; status=%u; size=%u",
428                         __func__, status, curDataSize);
429     status = NFA_RwWriteNDef(buffer, curDataSize);
430   } else {
431     DLOG_IF(INFO, nfc_debug_enabled)
432         << StringPrintf("%s: NFA_RwWriteNDef", __func__);
433     status = NFA_RwWriteNDef(p_data, bytes.size());
434   }
435 
436   if (status != NFA_STATUS_OK) {
437     LOG(ERROR) << StringPrintf("%s: write/format error=%d", __func__, status);
438     goto TheEnd;
439   }
440 
441   /* Wait for write completion status */
442   sWriteOk = false;
443   if (sem_wait(&sWriteSem)) {
444     LOG(ERROR) << StringPrintf("%s: wait semaphore (errno=0x%08x)", __func__,
445                                errno);
446     goto TheEnd;
447   }
448 
449   result = sWriteOk;
450 
451 TheEnd:
452   /* Destroy semaphore */
453   if (sem_destroy(&sWriteSem)) {
454     LOG(ERROR) << StringPrintf("%s: failed destroy semaphore (errno=0x%08x)",
455                                __func__, errno);
456   }
457   sWriteWaitingForComplete = JNI_FALSE;
458   DLOG_IF(INFO, nfc_debug_enabled)
459       << StringPrintf("%s: exit; result=%d", __func__, result);
460   return result;
461 }
462 
463 /*******************************************************************************
464 **
465 ** Function:        nativeNfcTag_doConnectStatus
466 **
467 ** Description:     Receive the completion status of connect operation.
468 **                  isConnectOk: Status of the operation.
469 **
470 ** Returns:         None
471 **
472 *******************************************************************************/
nativeNfcTag_doConnectStatus(jboolean isConnectOk)473 void nativeNfcTag_doConnectStatus(jboolean isConnectOk) {
474   if (sConnectWaitingForComplete != JNI_FALSE) {
475     sConnectWaitingForComplete = JNI_FALSE;
476     sConnectOk = isConnectOk;
477     SyncEventGuard g(sReconnectEvent);
478     sReconnectEvent.notifyOne();
479   }
480 }
481 
482 /*******************************************************************************
483 **
484 ** Function:        nativeNfcTag_doDeactivateStatus
485 **
486 ** Description:     Receive the completion status of deactivate operation.
487 **
488 ** Returns:         None
489 **
490 *******************************************************************************/
nativeNfcTag_doDeactivateStatus(int status)491 void nativeNfcTag_doDeactivateStatus(int status) {
492   sGotDeactivate = (status == 0);
493 
494   SyncEventGuard g(sReconnectEvent);
495   sReconnectEvent.notifyOne();
496 }
497 
498 /*******************************************************************************
499 **
500 ** Function:        nativeNfcTag_doConnect
501 **
502 ** Description:     Connect to the tag in RF field.
503 **                  e: JVM environment.
504 **                  o: Java object.
505 **                  targetHandle: Handle of the tag.
506 **
507 ** Returns:         Must return NXP status code, which NFC service expects.
508 **
509 *******************************************************************************/
nativeNfcTag_doConnect(JNIEnv *,jobject,jint targetHandle)510 static jint nativeNfcTag_doConnect(JNIEnv*, jobject, jint targetHandle) {
511   DLOG_IF(INFO, nfc_debug_enabled)
512       << StringPrintf("%s: targetHandle = %d", __func__, targetHandle);
513   int i = targetHandle;
514   NfcTag& natTag = NfcTag::getInstance();
515   int retCode = NFCSTATUS_SUCCESS;
516 
517   sIsoDepPresCheckCnt = 0;
518   sPresCheckErrCnt = 0;
519   sIsoDepPresCheckAlternate = false;
520 
521   if (i >= NfcTag::MAX_NUM_TECHNOLOGY) {
522     LOG(ERROR) << StringPrintf("%s: Handle not found", __func__);
523     retCode = NFCSTATUS_FAILED;
524     goto TheEnd;
525   }
526 
527   if (natTag.getActivationState() != NfcTag::Active) {
528     LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__);
529     retCode = NFCSTATUS_FAILED;
530     goto TheEnd;
531   }
532 
533   sCurrentConnectedTargetType = natTag.mTechList[i];
534   sCurrentConnectedTargetProtocol = natTag.mTechLibNfcTypes[i];
535   sCurrentConnectedHandle = targetHandle;
536 
537   if (sCurrentConnectedTargetProtocol != NFC_PROTOCOL_ISO_DEP &&
538       sCurrentConnectedTargetProtocol != NFC_PROTOCOL_MIFARE) {
539     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
540         "%s() Nfc type = %d, do nothing for non ISO_DEP and non Mifare ",
541         __func__, sCurrentConnectedTargetProtocol);
542     retCode = NFCSTATUS_SUCCESS;
543     goto TheEnd;
544   }
545 
546   if (sCurrentConnectedTargetType == TARGET_TYPE_ISO14443_3A ||
547       sCurrentConnectedTargetType == TARGET_TYPE_ISO14443_3B) {
548 
549       if (sCurrentConnectedTargetProtocol != NFC_PROTOCOL_MIFARE) {
550         DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
551         "%s: switching to tech: %d need to switch rf intf to frame", __func__,
552         sCurrentConnectedTargetType);
553         retCode = switchRfInterface(NFA_INTERFACE_FRAME) ? NFA_STATUS_OK
554                                                          : NFA_STATUS_FAILED;
555       }
556   } else if (sCurrentConnectedTargetType == TARGET_TYPE_MIFARE_CLASSIC) {
557     retCode = switchRfInterface(NFA_INTERFACE_MIFARE) ? NFA_STATUS_OK
558                                                       : NFA_STATUS_FAILED;
559   } else {
560     retCode = switchRfInterface(NFA_INTERFACE_ISO_DEP) ? NFA_STATUS_OK
561                                                        : NFA_STATUS_FAILED;
562   }
563 
564 TheEnd:
565   DLOG_IF(INFO, nfc_debug_enabled)
566       << StringPrintf("%s: exit 0x%X", __func__, retCode);
567   return retCode;
568 }
569 
570 /*******************************************************************************
571 **
572 ** Function:        reSelect
573 **
574 ** Description:     Deactivates the tag and re-selects it with the specified
575 **                  rf interface.
576 **
577 ** Returns:         status code, 0 on success, 1 on failure,
578 **                  146 (defined in service) on tag lost
579 **
580 *******************************************************************************/
reSelect(tNFA_INTF_TYPE rfInterface,bool fSwitchIfNeeded)581 static int reSelect(tNFA_INTF_TYPE rfInterface, bool fSwitchIfNeeded) {
582   DLOG_IF(INFO, nfc_debug_enabled)
583       << StringPrintf("%s: enter; rf intf = %d, current intf = %d", __func__,
584                       rfInterface, sCurrentRfInterface);
585 
586   sRfInterfaceMutex.lock();
587 
588   if (fSwitchIfNeeded && (rfInterface == sCurrentRfInterface)) {
589     // already in the requested interface
590     sRfInterfaceMutex.unlock();
591     return 0;  // success
592   }
593 
594   NfcTag& natTag = NfcTag::getInstance();
595 
596   tNFA_STATUS status = NFA_STATUS_OK;
597   int rVal = 1;
598 
599   do {
600     // if tag has shutdown, abort this method
601     if (NfcTag::getInstance().isNdefDetectionTimedOut()) {
602       DLOG_IF(INFO, nfc_debug_enabled)
603           << StringPrintf("%s: ndef detection timeout; break", __func__);
604       rVal = STATUS_CODE_TARGET_LOST;
605       break;
606     }
607     if ((sCurrentRfInterface == NFA_INTERFACE_FRAME) &&
608         (NFC_GetNCIVersion() >= NCI_VERSION_2_0)) {
609       {
610         SyncEventGuard g3(sReconnectEvent);
611         if (sCurrentActivatedProtocl == NFA_PROTOCOL_T2T) {
612           status = NFA_SendRawFrame(RW_TAG_SLP_REQ, sizeof(RW_TAG_SLP_REQ), 0);
613         } else if (sCurrentActivatedProtocl == NFA_PROTOCOL_ISO_DEP) {
614           status = NFA_SendRawFrame(RW_DESELECT_REQ,
615                                     sizeof(RW_DESELECT_REQ), 0);
616         }
617         sReconnectEvent.wait(4);
618         if (status != NFA_STATUS_OK) {
619           LOG(ERROR) << StringPrintf("%s: send error=%d", __func__, status);
620           break;
621         }
622       }
623     }
624 
625     {
626       SyncEventGuard g(sReconnectEvent);
627       gIsTagDeactivating = true;
628       sGotDeactivate = false;
629       DLOG_IF(INFO, nfc_debug_enabled)
630           << StringPrintf("%s: deactivate to sleep", __func__);
631       if (NFA_STATUS_OK !=
632           (status = NFA_Deactivate(TRUE)))  // deactivate to sleep state
633       {
634         LOG(ERROR) << StringPrintf("%s: deactivate failed, status = %d",
635                                    __func__, status);
636         break;
637       }
638 
639       if (sReconnectEvent.wait(1000) == false)  // if timeout occurred
640       {
641         LOG(ERROR) << StringPrintf("%s: timeout waiting for deactivate",
642                                    __func__);
643       }
644     }
645 
646     if (!sGotDeactivate) {
647       rVal = STATUS_CODE_TARGET_LOST;
648       break;
649     }
650 
651     if (NfcTag::getInstance().getActivationState() != NfcTag::Sleep) {
652       LOG(ERROR) << StringPrintf("%s: tag is not in sleep", __func__);
653       rVal = STATUS_CODE_TARGET_LOST;
654       break;
655     }
656 
657     gIsTagDeactivating = false;
658 
659     {
660       SyncEventGuard g2(sReconnectEvent);
661 
662       sConnectWaitingForComplete = JNI_TRUE;
663       DLOG_IF(INFO, nfc_debug_enabled)
664           << StringPrintf("%s: select interface %u", __func__, rfInterface);
665       gIsSelectingRfInterface = true;
666       if (NFA_STATUS_OK !=
667           (status = NFA_Select(natTag.mTechHandles[sCurrentConnectedHandle],
668                                natTag.mTechLibNfcTypes[sCurrentConnectedHandle],
669                                rfInterface))) {
670         LOG(ERROR) << StringPrintf("%s: NFA_Select failed, status = %d",
671                                    __func__, status);
672         break;
673       }
674 
675       sConnectOk = false;
676       if (sReconnectEvent.wait(1000) == false)  // if timeout occurred
677       {
678         LOG(ERROR) << StringPrintf("%s: timeout waiting for select", __func__);
679         break;
680       }
681     }
682 
683     /*Retry logic in case of core Generic error while selecting a tag*/
684     if (sConnectOk == false) {
685       LOG(ERROR) << StringPrintf("%s: waiting for Card to be activated",
686                                  __func__);
687       int retry = 0;
688       sConnectWaitingForComplete = JNI_TRUE;
689       do {
690         SyncEventGuard reselectEvent(sReconnectEvent);
691         if (sReconnectEvent.wait(500) == false) {  // if timeout occurred
692           LOG(ERROR) << StringPrintf("%s: timeout ", __func__);
693         }
694         retry++;
695         LOG(ERROR) << StringPrintf("%s: waiting for Card to be activated %x %x",
696                                    __func__, retry, sConnectOk);
697       } while (sConnectOk == false && retry < 3);
698     }
699 
700     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
701         "%s: select completed; sConnectOk=%d", __func__, sConnectOk);
702     if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
703       LOG(ERROR) << StringPrintf("%s: tag is not active", __func__);
704       rVal = STATUS_CODE_TARGET_LOST;
705       break;
706     }
707     if (sConnectOk) {
708       rVal = 0;  // success
709       sCurrentRfInterface = rfInterface;
710     } else {
711       rVal = 1;
712     }
713   } while (0);
714 
715   sConnectWaitingForComplete = JNI_FALSE;
716   gIsTagDeactivating = false;
717   gIsSelectingRfInterface = false;
718   sRfInterfaceMutex.unlock();
719   DLOG_IF(INFO, nfc_debug_enabled)
720       << StringPrintf("%s: exit; status=%d", __func__, rVal);
721   return rVal;
722 }
723 
724 /*******************************************************************************
725 **
726 ** Function:        switchRfInterface
727 **
728 ** Description:     Switch controller's RF interface to frame, ISO-DEP, or
729 *NFC-DEP.
730 **                  rfInterface: Type of RF interface.
731 **
732 ** Returns:         True if ok.
733 **
734 *******************************************************************************/
switchRfInterface(tNFA_INTF_TYPE rfInterface)735 static bool switchRfInterface(tNFA_INTF_TYPE rfInterface) {
736   NfcTag& natTag = NfcTag::getInstance();
737 
738   if (sCurrentConnectedTargetProtocol != NFC_PROTOCOL_ISO_DEP &&
739       sCurrentConnectedTargetProtocol != NFC_PROTOCOL_MIFARE) {
740     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
741         "%s: protocol: %d not ISO_DEP and not Mifare, do nothing", __func__,
742         natTag.mTechLibNfcTypes[0]);
743     return true;
744   }
745 
746   DLOG_IF(INFO, nfc_debug_enabled)
747       << StringPrintf("%s: new rf intf = %d, cur rf intf = %d", __func__,
748                       rfInterface, sCurrentRfInterface);
749 
750   return (0 == reSelect(rfInterface, true));
751 }
752 
753 /*******************************************************************************
754 **
755 ** Function:        nativeNfcTag_doReconnect
756 **
757 ** Description:     Re-connect to the tag in RF field.
758 **                  e: JVM environment.
759 **                  o: Java object.
760 **
761 ** Returns:         Status code.
762 **
763 *******************************************************************************/
nativeNfcTag_doReconnect(JNIEnv *,jobject)764 static jint nativeNfcTag_doReconnect(JNIEnv*, jobject) {
765   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
766   int retCode = NFCSTATUS_SUCCESS;
767   NfcTag& natTag = NfcTag::getInstance();
768 
769   if (natTag.getActivationState() != NfcTag::Active) {
770     LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__);
771     retCode = NFCSTATUS_FAILED;
772     goto TheEnd;
773   }
774 
775   // special case for Kovio
776   if (sCurrentConnectedTargetProtocol == TARGET_TYPE_KOVIO_BARCODE) {
777     DLOG_IF(INFO, nfc_debug_enabled)
778         << StringPrintf("%s: fake out reconnect for Kovio", __func__);
779     goto TheEnd;
780   }
781 
782   // this is only supported for type 2 or 4 (ISO_DEP) tags
783   if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_ISO_DEP)
784     retCode = reSelect(NFA_INTERFACE_ISO_DEP, false);
785   else if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_T2T)
786     retCode = reSelect(NFA_INTERFACE_FRAME, false);
787   else if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE)
788     retCode = reSelect(NFA_INTERFACE_MIFARE, false);
789 
790 TheEnd:
791   DLOG_IF(INFO, nfc_debug_enabled)
792       << StringPrintf("%s: exit 0x%X", __func__, retCode);
793   return retCode;
794 }
795 
796 /*******************************************************************************
797 **
798 ** Function:        nativeNfcTag_doHandleReconnect
799 **
800 ** Description:     Re-connect to the tag in RF field.
801 **                  e: JVM environment.
802 **                  o: Java object.
803 **                  targetHandle: Handle of the tag.
804 **
805 ** Returns:         Status code.
806 **
807 *******************************************************************************/
nativeNfcTag_doHandleReconnect(JNIEnv * e,jobject o,jint targetHandle)808 static jint nativeNfcTag_doHandleReconnect(JNIEnv* e, jobject o,
809                                            jint targetHandle) {
810   DLOG_IF(INFO, nfc_debug_enabled)
811       << StringPrintf("%s: targetHandle = %d", __func__, targetHandle);
812   return nativeNfcTag_doConnect(e, o, targetHandle);
813 }
814 
815 /*******************************************************************************
816 **
817 ** Function:        nativeNfcTag_doDisconnect
818 **
819 ** Description:     Deactivate the RF field.
820 **                  e: JVM environment.
821 **                  o: Java object.
822 **
823 ** Returns:         True if ok.
824 **
825 *******************************************************************************/
nativeNfcTag_doDisconnect(JNIEnv *,jobject)826 jboolean nativeNfcTag_doDisconnect(JNIEnv*, jobject) {
827   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
828   tNFA_STATUS nfaStat = NFA_STATUS_OK;
829 
830   NfcTag::getInstance().resetAllTransceiveTimeouts();
831 
832   if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
833     LOG(WARNING) << StringPrintf("%s: tag already deactivated", __func__);
834     goto TheEnd;
835   }
836 
837   nfaStat = NFA_Deactivate(FALSE);
838   if (nfaStat != NFA_STATUS_OK)
839     LOG(ERROR) << StringPrintf("%s: deactivate failed; error=0x%X", __func__,
840                                nfaStat);
841 
842 TheEnd:
843   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
844   return (nfaStat == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
845 }
846 
847 /*******************************************************************************
848 **
849 ** Function:        nativeNfcTag_doTransceiveStatus
850 **
851 ** Description:     Receive the completion status of transceive operation.
852 **                  status: operation status.
853 **                  buf: Contains tag's response.
854 **                  bufLen: Length of buffer.
855 **
856 ** Returns:         None
857 **
858 *******************************************************************************/
nativeNfcTag_doTransceiveStatus(tNFA_STATUS status,uint8_t * buf,uint32_t bufLen)859 void nativeNfcTag_doTransceiveStatus(tNFA_STATUS status, uint8_t* buf,
860                                      uint32_t bufLen) {
861   SyncEventGuard g(sTransceiveEvent);
862   DLOG_IF(INFO, nfc_debug_enabled)
863       << StringPrintf("%s: data len=%d", __func__, bufLen);
864 
865   if (!sWaitingForTransceive) {
866     LOG(ERROR) << StringPrintf("%s: drop data", __func__);
867     return;
868   }
869   sRxDataStatus = status;
870   if (sRxDataStatus == NFA_STATUS_OK || sRxDataStatus == NFC_STATUS_CONTINUE)
871     sRxDataBuffer.append(buf, bufLen);
872 
873   if (sRxDataStatus == NFA_STATUS_OK) sTransceiveEvent.notifyOne();
874 }
875 
nativeNfcTag_notifyRfTimeout()876 void nativeNfcTag_notifyRfTimeout() {
877   SyncEventGuard g(sTransceiveEvent);
878   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
879       "%s: waiting for transceive: %d", __func__, sWaitingForTransceive);
880   if (!sWaitingForTransceive) return;
881 
882   sTransceiveRfTimeout = true;
883 
884   sTransceiveEvent.notifyOne();
885 }
886 
887 /*******************************************************************************
888 **
889 ** Function:        nativeNfcTag_doTransceive
890 **
891 ** Description:     Send raw data to the tag; receive tag's response.
892 **                  e: JVM environment.
893 **                  o: Java object.
894 **                  raw: Not used.
895 **                  statusTargetLost: Whether tag responds or times out.
896 **
897 ** Returns:         Response from tag.
898 **
899 *******************************************************************************/
nativeNfcTag_doTransceive(JNIEnv * e,jobject o,jbyteArray data,jboolean raw,jintArray statusTargetLost)900 static jbyteArray nativeNfcTag_doTransceive(JNIEnv* e, jobject o,
901                                             jbyteArray data, jboolean raw,
902                                             jintArray statusTargetLost) {
903   int timeout =
904       NfcTag::getInstance().getTransceiveTimeout(sCurrentConnectedTargetType);
905   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
906       "%s: enter; raw=%u; timeout = %d", __func__, raw, timeout);
907 
908   bool waitOk = false;
909   bool isNack = false;
910   jint* targetLost = NULL;
911   tNFA_STATUS status;
912 
913   if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
914     if (statusTargetLost) {
915       targetLost = e->GetIntArrayElements(statusTargetLost, 0);
916       if (targetLost)
917         *targetLost = 1;  // causes NFC service to throw TagLostException
918       e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0);
919     }
920     DLOG_IF(INFO, nfc_debug_enabled)
921         << StringPrintf("%s: tag not active", __func__);
922     return NULL;
923   }
924 
925   NfcTag& natTag = NfcTag::getInstance();
926 
927   // get input buffer and length from java call
928   ScopedByteArrayRO bytes(e, data);
929   uint8_t* buf = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(
930       &bytes[0]));  // TODO: API bug; NFA_SendRawFrame should take const*!
931   size_t bufLen = bytes.size();
932 
933   if (statusTargetLost) {
934     targetLost = e->GetIntArrayElements(statusTargetLost, 0);
935     if (targetLost) *targetLost = 0;  // success, tag is still present
936   }
937 
938   sSwitchBackTimer.kill();
939   ScopedLocalRef<jbyteArray> result(e, NULL);
940   do {
941     {
942       SyncEventGuard g(sTransceiveEvent);
943       sTransceiveRfTimeout = false;
944       sWaitingForTransceive = true;
945       sRxDataStatus = NFA_STATUS_OK;
946       sRxDataBuffer.clear();
947 
948       status = NFA_SendRawFrame(buf, bufLen,
949                                 NFA_DM_DEFAULT_PRESENCE_CHECK_START_DELAY);
950       if (status != NFA_STATUS_OK) {
951         LOG(ERROR) << StringPrintf("%s: fail send; error=%d", __func__, status);
952         break;
953       }
954       waitOk = sTransceiveEvent.wait(timeout);
955     }
956 
957     if (waitOk == false || sTransceiveRfTimeout)  // if timeout occurred
958     {
959       LOG(ERROR) << StringPrintf("%s: wait response timeout", __func__);
960       if (targetLost)
961         *targetLost = 1;  // causes NFC service to throw TagLostException
962       break;
963     }
964 
965     if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
966       LOG(ERROR) << StringPrintf("%s: already deactivated", __func__);
967       if (targetLost)
968         *targetLost = 1;  // causes NFC service to throw TagLostException
969       break;
970     }
971 
972     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
973         "%s: response %zu bytes", __func__, sRxDataBuffer.size());
974 
975     if ((natTag.getProtocol() == NFA_PROTOCOL_T2T) &&
976         natTag.isT2tNackResponse(sRxDataBuffer.data(), sRxDataBuffer.size())) {
977       isNack = true;
978     }
979 
980     if (sRxDataBuffer.size() > 0) {
981       if (isNack) {
982         // Some Mifare Ultralight C tags enter the HALT state after it
983         // responds with a NACK.  Need to perform a "reconnect" operation
984         // to wake it.
985         DLOG_IF(INFO, nfc_debug_enabled)
986             << StringPrintf("%s: try reconnect", __func__);
987         nativeNfcTag_doReconnect(NULL, NULL);
988         DLOG_IF(INFO, nfc_debug_enabled)
989             << StringPrintf("%s: reconnect finish", __func__);
990       } else if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
991         uint32_t transDataLen = static_cast<uint32_t>(sRxDataBuffer.size());
992         uint8_t* transData = (uint8_t*)sRxDataBuffer.data();
993         bool doReconnect = false;
994 
995         doReconnect =
996             ((transDataLen == 1) && (transData[0] != 0x00)) ? true : false;
997 
998         if (doReconnect) {
999           nativeNfcTag_doReconnect(e, o);
1000         } else {
1001           if (transDataLen != 0) {
1002             result.reset(e->NewByteArray(transDataLen));
1003             if (result.get() != NULL) {
1004               e->SetByteArrayRegion(result.get(), 0, transDataLen,
1005                                   (const jbyte*)transData);
1006             } else
1007               LOG(ERROR) << StringPrintf("%s: Failed to allocate java byte array",
1008                                        __func__);
1009           }
1010         }
1011       } else {
1012         // marshall data to java for return
1013         result.reset(e->NewByteArray(sRxDataBuffer.size()));
1014         if (result.get() != NULL) {
1015           e->SetByteArrayRegion(result.get(), 0, sRxDataBuffer.size(),
1016                                 (const jbyte*)sRxDataBuffer.data());
1017         } else
1018           LOG(ERROR) << StringPrintf("%s: Failed to allocate java byte array",
1019                                      __func__);
1020       }  // else a nack is treated as a transceive failure to the upper layers
1021 
1022       sRxDataBuffer.clear();
1023     }
1024   } while (0);
1025 
1026   sWaitingForTransceive = false;
1027   if (targetLost) e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0);
1028 
1029   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
1030   return result.release();
1031 }
1032 
1033 /*******************************************************************************
1034 **
1035 ** Function:        nativeNfcTag_doGetNdefType
1036 **
1037 ** Description:     Retrieve the type of tag.
1038 **                  e: JVM environment.
1039 **                  o: Java object.
1040 **                  libnfcType: Type of tag represented by JNI.
1041 **                  javaType: Not used.
1042 **
1043 ** Returns:         Type of tag represented by NFC Service.
1044 **
1045 *******************************************************************************/
nativeNfcTag_doGetNdefType(JNIEnv *,jobject,jint libnfcType,jint javaType)1046 static jint nativeNfcTag_doGetNdefType(JNIEnv*, jobject, jint libnfcType,
1047                                        jint javaType) {
1048   DLOG_IF(INFO, nfc_debug_enabled)
1049       << StringPrintf("%s: enter; libnfc type=%d; java type=%d", __func__,
1050                       libnfcType, javaType);
1051   jint ndefType = NDEF_UNKNOWN_TYPE;
1052 
1053   // For NFA, libnfcType is mapped to the protocol value received
1054   // in the NFA_ACTIVATED_EVT and NFA_DISC_RESULT_EVT event.
1055   if (NFA_PROTOCOL_T1T == libnfcType) {
1056     ndefType = NDEF_TYPE1_TAG;
1057   } else if (NFA_PROTOCOL_T2T == libnfcType) {
1058     ndefType = NDEF_TYPE2_TAG;
1059   } else if (NFA_PROTOCOL_T3T == libnfcType) {
1060     ndefType = NDEF_TYPE3_TAG;
1061   } else if (NFA_PROTOCOL_ISO_DEP == libnfcType) {
1062     ndefType = NDEF_TYPE4_TAG;
1063   } else if (NFC_PROTOCOL_MIFARE == libnfcType) {
1064     ndefType = NDEF_MIFARE_CLASSIC_TAG;
1065   } else {
1066     /* NFA_PROTOCOL_T5T, NFA_PROTOCOL_INVALID and others */
1067     ndefType = NDEF_UNKNOWN_TYPE;
1068   }
1069   DLOG_IF(INFO, nfc_debug_enabled)
1070       << StringPrintf("%s: exit; ndef type=%d", __func__, ndefType);
1071   return ndefType;
1072 }
1073 
1074 /*******************************************************************************
1075 **
1076 ** Function:        nativeNfcTag_doCheckNdefResult
1077 **
1078 ** Description:     Receive the result of checking whether the tag contains a
1079 *NDEF
1080 **                  message.  Called by the NFA_NDEF_DETECT_EVT.
1081 **                  status: Status of the operation.
1082 **                  maxSize: Maximum size of NDEF message.
1083 **                  currentSize: Current size of NDEF message.
1084 **                  flags: Indicate various states.
1085 **
1086 ** Returns:         None
1087 **
1088 *******************************************************************************/
nativeNfcTag_doCheckNdefResult(tNFA_STATUS status,uint32_t maxSize,uint32_t currentSize,uint8_t flags)1089 void nativeNfcTag_doCheckNdefResult(tNFA_STATUS status, uint32_t maxSize,
1090                                     uint32_t currentSize, uint8_t flags) {
1091   // this function's flags parameter is defined using the following macros
1092   // in nfc/include/rw_api.h;
1093   //#define RW_NDEF_FL_READ_ONLY  0x01    /* Tag is read only              */
1094   //#define RW_NDEF_FL_FORMATED   0x02    /* Tag formated for NDEF         */
1095   //#define RW_NDEF_FL_SUPPORTED  0x04    /* NDEF supported by the tag     */
1096   //#define RW_NDEF_FL_UNKNOWN    0x08    /* Unable to find if tag is ndef
1097   // capable/formated/read only */ #define RW_NDEF_FL_FORMATABLE 0x10    /* Tag
1098   // supports format operation */
1099 
1100   if (!sCheckNdefWaitingForComplete) {
1101     LOG(ERROR) << StringPrintf("%s: not waiting", __func__);
1102     return;
1103   }
1104 
1105   if (flags & RW_NDEF_FL_READ_ONLY)
1106     DLOG_IF(INFO, nfc_debug_enabled)
1107         << StringPrintf("%s: flag read-only", __func__);
1108   if (flags & RW_NDEF_FL_FORMATED)
1109     DLOG_IF(INFO, nfc_debug_enabled)
1110         << StringPrintf("%s: flag formatted for ndef", __func__);
1111   if (flags & RW_NDEF_FL_SUPPORTED)
1112     DLOG_IF(INFO, nfc_debug_enabled)
1113         << StringPrintf("%s: flag ndef supported", __func__);
1114   if (flags & RW_NDEF_FL_UNKNOWN)
1115     DLOG_IF(INFO, nfc_debug_enabled)
1116         << StringPrintf("%s: flag all unknown", __func__);
1117   if (flags & RW_NDEF_FL_FORMATABLE)
1118     DLOG_IF(INFO, nfc_debug_enabled)
1119         << StringPrintf("%s: flag formattable", __func__);
1120 
1121   sCheckNdefWaitingForComplete = JNI_FALSE;
1122   sCheckNdefStatus = status;
1123   if (sCheckNdefStatus != NFA_STATUS_OK &&
1124       sCheckNdefStatus != NFA_STATUS_TIMEOUT)
1125     sCheckNdefStatus = NFA_STATUS_FAILED;
1126   sCheckNdefCapable = false;  // assume tag is NOT ndef capable
1127   if (sCheckNdefStatus == NFA_STATUS_OK) {
1128     // NDEF content is on the tag
1129     sCheckNdefMaxSize = maxSize;
1130     sCheckNdefCurrentSize = currentSize;
1131     sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
1132     sCheckNdefCapable = true;
1133   } else if (sCheckNdefStatus == NFA_STATUS_FAILED) {
1134     // no NDEF content on the tag
1135     sCheckNdefMaxSize = 0;
1136     sCheckNdefCurrentSize = 0;
1137     sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
1138     if ((flags & RW_NDEF_FL_UNKNOWN) == 0)  // if stack understands the tag
1139     {
1140       if (flags & RW_NDEF_FL_SUPPORTED)  // if tag is ndef capable
1141         sCheckNdefCapable = true;
1142     }
1143   } else {
1144     LOG(ERROR) << StringPrintf("%s: unknown status=0x%X", __func__, status);
1145     sCheckNdefMaxSize = 0;
1146     sCheckNdefCurrentSize = 0;
1147     sCheckNdefCardReadOnly = false;
1148   }
1149   sem_post(&sCheckNdefSem);
1150 }
1151 
1152 /*******************************************************************************
1153 **
1154 ** Function:        nativeNfcTag_doCheckNdef
1155 **
1156 ** Description:     Does the tag contain a NDEF message?
1157 **                  e: JVM environment.
1158 **                  o: Java object.
1159 **                  ndefInfo: NDEF info.
1160 **
1161 ** Returns:         Status code; 0 is success.
1162 **
1163 *******************************************************************************/
nativeNfcTag_doCheckNdef(JNIEnv * e,jobject o,jintArray ndefInfo)1164 static jint nativeNfcTag_doCheckNdef(JNIEnv* e, jobject o, jintArray ndefInfo) {
1165   tNFA_STATUS status = NFA_STATUS_FAILED;
1166   jint* ndef = NULL;
1167 
1168   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
1169 
1170   // special case for Kovio
1171   if (sCurrentConnectedTargetProtocol == TARGET_TYPE_KOVIO_BARCODE) {
1172     DLOG_IF(INFO, nfc_debug_enabled)
1173         << StringPrintf("%s: Kovio tag, no NDEF", __func__);
1174     ndef = e->GetIntArrayElements(ndefInfo, 0);
1175     ndef[0] = 0;
1176     ndef[1] = NDEF_MODE_READ_ONLY;
1177     e->ReleaseIntArrayElements(ndefInfo, ndef, 0);
1178     return NFA_STATUS_FAILED;
1179   } else if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1180     nativeNfcTag_doReconnect(e, o);
1181   }
1182 
1183   /* Create the write semaphore */
1184   if (sem_init(&sCheckNdefSem, 0, 0) == -1) {
1185     LOG(ERROR) << StringPrintf(
1186         "%s: Check NDEF semaphore creation failed (errno=0x%08x)", __func__,
1187         errno);
1188     return JNI_FALSE;
1189   }
1190 
1191   if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
1192     LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__);
1193     goto TheEnd;
1194   }
1195 
1196   DLOG_IF(INFO, nfc_debug_enabled)
1197       << StringPrintf("%s: try NFA_RwDetectNDef", __func__);
1198   sCheckNdefWaitingForComplete = JNI_TRUE;
1199 
1200   status = NFA_RwDetectNDef();
1201 
1202   if (status != NFA_STATUS_OK) {
1203     LOG(ERROR) << StringPrintf("%s: NFA_RwDetectNDef failed, status = 0x%X",
1204                                __func__, status);
1205     goto TheEnd;
1206   }
1207 
1208   /* Wait for check NDEF completion status */
1209   if (sem_wait(&sCheckNdefSem)) {
1210     LOG(ERROR) << StringPrintf(
1211         "%s: Failed to wait for check NDEF semaphore (errno=0x%08x)", __func__,
1212         errno);
1213     goto TheEnd;
1214   }
1215 
1216   if (sCheckNdefStatus == NFA_STATUS_OK) {
1217     // stack found a NDEF message on the tag
1218     ndef = e->GetIntArrayElements(ndefInfo, 0);
1219     if (NfcTag::getInstance().getProtocol() == NFA_PROTOCOL_T1T)
1220       ndef[0] = NfcTag::getInstance().getT1tMaxMessageSize();
1221     else
1222       ndef[0] = sCheckNdefMaxSize;
1223     if (sCheckNdefCardReadOnly)
1224       ndef[1] = NDEF_MODE_READ_ONLY;
1225     else
1226       ndef[1] = NDEF_MODE_READ_WRITE;
1227     e->ReleaseIntArrayElements(ndefInfo, ndef, 0);
1228     status = NFA_STATUS_OK;
1229   } else if (sCheckNdefStatus == NFA_STATUS_FAILED) {
1230     // stack did not find a NDEF message on the tag;
1231     ndef = e->GetIntArrayElements(ndefInfo, 0);
1232     if (NfcTag::getInstance().getProtocol() == NFA_PROTOCOL_T1T)
1233       ndef[0] = NfcTag::getInstance().getT1tMaxMessageSize();
1234     else
1235       ndef[0] = sCheckNdefMaxSize;
1236     if (sCheckNdefCardReadOnly)
1237       ndef[1] = NDEF_MODE_READ_ONLY;
1238     else
1239       ndef[1] = NDEF_MODE_READ_WRITE;
1240     e->ReleaseIntArrayElements(ndefInfo, ndef, 0);
1241     status = NFA_STATUS_FAILED;
1242   } else {
1243     DLOG_IF(INFO, nfc_debug_enabled)
1244         << StringPrintf("%s: unknown status 0x%X", __func__, sCheckNdefStatus);
1245     status = sCheckNdefStatus;
1246   }
1247 
1248   /* Reconnect Mifare Classic Tag for furture use */
1249   if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1250     nativeNfcTag_doReconnect(e, o);
1251   }
1252 
1253 TheEnd:
1254   /* Destroy semaphore */
1255   if (sem_destroy(&sCheckNdefSem)) {
1256     LOG(ERROR) << StringPrintf(
1257         "%s: Failed to destroy check NDEF semaphore (errno=0x%08x)", __func__,
1258         errno);
1259   }
1260   sCheckNdefWaitingForComplete = JNI_FALSE;
1261   DLOG_IF(INFO, nfc_debug_enabled)
1262       << StringPrintf("%s: exit; status=0x%X", __func__, status);
1263   return status;
1264 }
1265 
1266 /*******************************************************************************
1267 **
1268 ** Function:        nativeNfcTag_resetPresenceCheck
1269 **
1270 ** Description:     Reset variables related to presence-check.
1271 **
1272 ** Returns:         None
1273 **
1274 *******************************************************************************/
nativeNfcTag_resetPresenceCheck()1275 void nativeNfcTag_resetPresenceCheck() {
1276   sIsTagPresent = true;
1277   sIsoDepPresCheckCnt = 0;
1278   sPresCheckErrCnt = 0;
1279   sIsoDepPresCheckAlternate = false;
1280   sPresCheckStatus = 0;
1281 }
1282 
1283 /*******************************************************************************
1284 **
1285 ** Function:        nativeNfcTag_doPresenceCheckResult
1286 **
1287 ** Description:     Receive the result of presence-check.
1288 **                  status: Result of presence-check.
1289 **
1290 ** Returns:         None
1291 **
1292 *******************************************************************************/
nativeNfcTag_doPresenceCheckResult(tNFA_STATUS status)1293 void nativeNfcTag_doPresenceCheckResult(tNFA_STATUS status) {
1294   SyncEventGuard guard(sPresenceCheckEvent);
1295   sIsTagPresent = status == NFA_STATUS_OK;
1296   sPresCheckStatus = status;
1297   sPresenceCheckEvent.notifyOne();
1298 }
1299 
1300 /*******************************************************************************
1301 **
1302 ** Function:        nativeNfcTag_doPresenceCheck
1303 **
1304 ** Description:     Check if the tag is in the RF field.
1305 **                  e: JVM environment.
1306 **                  o: Java object.
1307 **
1308 ** Returns:         True if tag is in RF field.
1309 **
1310 *******************************************************************************/
nativeNfcTag_doPresenceCheck(JNIEnv *,jobject)1311 static jboolean nativeNfcTag_doPresenceCheck(JNIEnv*, jobject) {
1312   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1313   tNFA_STATUS status = NFA_STATUS_OK;
1314   bool isPresent = false;
1315 
1316   // Special case for Kovio.  The deactivation would have already occurred
1317   // but was ignored so that normal tag opertions could complete.  Now we
1318   // want to process as if the deactivate just happened.
1319   if (sCurrentConnectedTargetProtocol == TARGET_TYPE_KOVIO_BARCODE) {
1320     DLOG_IF(INFO, nfc_debug_enabled)
1321         << StringPrintf("%s: Kovio, force deactivate handling", __func__);
1322     tNFA_DEACTIVATED deactivated = {NFA_DEACTIVATE_TYPE_IDLE};
1323     {
1324       SyncEventGuard g(gDeactivatedEvent);
1325       gActivated = false;  // guard this variable from multi-threaded access
1326       gDeactivatedEvent.notifyOne();
1327     }
1328 
1329     NfcTag::getInstance().setDeactivationState(deactivated);
1330     nativeNfcTag_resetPresenceCheck();
1331     NfcTag::getInstance().connectionEventHandler(NFA_DEACTIVATED_EVT, NULL);
1332     nativeNfcTag_abortWaits();
1333     NfcTag::getInstance().abort();
1334 
1335     return JNI_FALSE;
1336   }
1337 
1338   if (nfcManager_isNfcActive() == false) {
1339     DLOG_IF(INFO, nfc_debug_enabled)
1340         << StringPrintf("%s: NFC is no longer active.", __func__);
1341     return JNI_FALSE;
1342   }
1343 
1344   if (!sRfInterfaceMutex.tryLock()) {
1345     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1346         "%s: tag is being reSelected assume it is present", __func__);
1347     return JNI_TRUE;
1348   }
1349 
1350   sRfInterfaceMutex.unlock();
1351 
1352   if (NfcTag::getInstance().isActivated() == false) {
1353     DLOG_IF(INFO, nfc_debug_enabled)
1354         << StringPrintf("%s: tag already deactivated", __func__);
1355     return JNI_FALSE;
1356   }
1357   {
1358     SyncEventGuard guard(sPresenceCheckEvent);
1359     tNFA_RW_PRES_CHK_OPTION method =
1360         NfcTag::getInstance().getPresenceCheckAlgorithm();
1361 
1362     if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_ISO_DEP) {
1363       if (method == NFA_RW_PRES_CHK_ISO_DEP_NAK) {
1364         sIsoDepPresCheckCnt++;
1365       }
1366       if (sIsoDepPresCheckAlternate == true) {
1367         method = NFA_RW_PRES_CHK_I_BLOCK;
1368       }
1369     }
1370 
1371     status = NFA_RwPresenceCheck(method);
1372     if (status == NFA_STATUS_OK) {
1373       isPresent = sPresenceCheckEvent.wait(2000);
1374 
1375       DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1376           "%s(%d): isPresent = %d", __FUNCTION__, __LINE__, isPresent);
1377 
1378       if (!sIsTagPresent &&
1379           (((sCurrentConnectedTargetProtocol == NFC_PROTOCOL_ISO_DEP) &&
1380             (method == NFA_RW_PRES_CHK_ISO_DEP_NAK)) ||
1381            ((sPresCheckStatus == NFA_STATUS_RF_FRAME_CORRUPTED) &&
1382             ((sCurrentConnectedTargetProtocol == NFC_PROTOCOL_T1T) ||
1383              (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_T2T) ||
1384              (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_T5T))) ||
1385            (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_T3T))) {
1386         sPresCheckErrCnt++;
1387 
1388         while (sPresCheckErrCnt <= 3) {
1389           DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1390               "%s(%d): pres check failed, try again (attempt #%d/3)",
1391               __FUNCTION__, __LINE__, sPresCheckErrCnt);
1392 
1393           status = NFA_RwPresenceCheck(method);
1394 
1395           if (status == NFA_STATUS_OK) {
1396             isPresent = sPresenceCheckEvent.wait(2000);
1397             DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1398                 "%s(%d): isPresent = %d", __FUNCTION__, __LINE__, isPresent);
1399 
1400             if (!isPresent) {
1401               break;
1402             } else if (isPresent && sIsTagPresent) {
1403               sPresCheckErrCnt = 0;
1404               break;
1405             } else {
1406               sPresCheckErrCnt++;
1407             }
1408           }
1409         }
1410       }
1411 
1412       if (isPresent && (sIsoDepPresCheckCnt == 1) && !sIsTagPresent) {
1413         DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1414             "%s(%d): Try alternate method in case tag does not support RNAK",
1415             __FUNCTION__, __LINE__);
1416 
1417         method = NFA_RW_PRES_CHK_I_BLOCK;
1418         sIsoDepPresCheckAlternate = true;
1419         status = NFA_RwPresenceCheck(method);
1420 
1421         if (status == NFA_STATUS_OK) {
1422           isPresent = sPresenceCheckEvent.wait(2000);
1423           DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1424               "%s(%d): isPresent = %d", __FUNCTION__, __LINE__, isPresent);
1425         }
1426       }
1427 
1428       isPresent = isPresent && sIsTagPresent;
1429     }
1430   }
1431 
1432   if (!isPresent) {
1433     DLOG_IF(INFO, nfc_debug_enabled)
1434         << StringPrintf("%s: tag absent", __func__);
1435 
1436     nativeNfcTag_resetPresenceCheck();
1437   }
1438 
1439   return isPresent ? JNI_TRUE : JNI_FALSE;
1440 }
1441 
1442 /*******************************************************************************
1443 **
1444 ** Function:        nativeNfcTag_doIsNdefFormatable
1445 **
1446 ** Description:     Can tag be formatted to store NDEF message?
1447 **                  e: JVM environment.
1448 **                  o: Java object.
1449 **                  libNfcType: Type of tag.
1450 **                  uidBytes: Tag's unique ID.
1451 **                  pollBytes: Data from activation.
1452 **                  actBytes: Data from activation.
1453 **
1454 ** Returns:         True if formattable.
1455 **
1456 *******************************************************************************/
nativeNfcTag_doIsNdefFormatable(JNIEnv * e,jobject o,jint,jbyteArray,jbyteArray,jbyteArray)1457 static jboolean nativeNfcTag_doIsNdefFormatable(JNIEnv* e, jobject o,
1458                                                 jint /*libNfcType*/, jbyteArray,
1459                                                 jbyteArray, jbyteArray) {
1460   jboolean isFormattable = JNI_FALSE;
1461   tNFC_PROTOCOL protocol = NfcTag::getInstance().getProtocol();
1462   if (NFA_PROTOCOL_T1T == protocol || NFA_PROTOCOL_T5T == protocol ||
1463       NFC_PROTOCOL_MIFARE == protocol) {
1464     isFormattable = JNI_TRUE;
1465   } else if (NFA_PROTOCOL_T3T == protocol) {
1466     isFormattable = NfcTag::getInstance().isFelicaLite() ? JNI_TRUE : JNI_FALSE;
1467   } else if (NFA_PROTOCOL_T2T == protocol) {
1468     isFormattable = (NfcTag::getInstance().isMifareUltralight() ||
1469                      NfcTag::getInstance().isInfineonMyDMove() ||
1470                      NfcTag::getInstance().isKovioType2Tag())
1471                         ? JNI_TRUE
1472                         : JNI_FALSE;
1473   } else if (NFA_PROTOCOL_ISO_DEP == protocol) {
1474     /**
1475      * Determines whether this is a formatable IsoDep tag - currectly only NXP
1476      * DESFire is supported.
1477      */
1478     uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00};
1479 
1480     if (NfcTag::getInstance().isMifareDESFire()) {
1481       /* Identifies as DESfire, use get version cmd to be sure */
1482       jbyteArray versionCmd = e->NewByteArray(5);
1483       e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd);
1484       jbyteArray respBytes =
1485           nativeNfcTag_doTransceive(e, o, versionCmd, JNI_TRUE, NULL);
1486       if (respBytes != NULL) {
1487         // Check whether the response matches a typical DESfire
1488         // response.
1489         // libNFC even does more advanced checking than we do
1490         // here, and will only format DESfire's with a certain
1491         // major/minor sw version and NXP as a manufacturer.
1492         // We don't want to do such checking here, to avoid
1493         // having to change code in multiple places.
1494         // A succesful (wrapped) DESFire getVersion command returns
1495         // 9 bytes, with byte 7 0x91 and byte 8 having status
1496         // code 0xAF (these values are fixed and well-known).
1497         int respLength = e->GetArrayLength(respBytes);
1498         uint8_t* resp = (uint8_t*)e->GetByteArrayElements(respBytes, NULL);
1499         if (respLength == 9 && resp[7] == 0x91 && resp[8] == 0xAF) {
1500           isFormattable = JNI_TRUE;
1501         }
1502         e->ReleaseByteArrayElements(respBytes, (jbyte*)resp, JNI_ABORT);
1503       }
1504     }
1505   }
1506 
1507   DLOG_IF(INFO, nfc_debug_enabled)
1508       << StringPrintf("%s: is formattable=%u", __func__, isFormattable);
1509   return isFormattable;
1510 }
1511 
1512 /*******************************************************************************
1513 **
1514 ** Function:        nativeNfcTag_doIsIsoDepNdefFormatable
1515 **
1516 ** Description:     Is ISO-DEP tag formattable?
1517 **                  e: JVM environment.
1518 **                  o: Java object.
1519 **                  pollBytes: Data from activation.
1520 **                  actBytes: Data from activation.
1521 **
1522 ** Returns:         True if formattable.
1523 **
1524 *******************************************************************************/
nativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv * e,jobject o,jbyteArray pollBytes,jbyteArray actBytes)1525 static jboolean nativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv* e, jobject o,
1526                                                       jbyteArray pollBytes,
1527                                                       jbyteArray actBytes) {
1528   uint8_t uidFake[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
1529   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1530   jbyteArray uidArray = e->NewByteArray(8);
1531   e->SetByteArrayRegion(uidArray, 0, 8, (jbyte*)uidFake);
1532   return nativeNfcTag_doIsNdefFormatable(e, o, 0, uidArray, pollBytes,
1533                                          actBytes);
1534 }
1535 
1536 /*******************************************************************************
1537 **
1538 ** Function:        nativeNfcTag_doNdefFormat
1539 **
1540 ** Description:     Format a tag so it can store NDEF message.
1541 **                  e: JVM environment.
1542 **                  o: Java object.
1543 **                  key: Not used.
1544 **
1545 ** Returns:         True if ok.
1546 **
1547 *******************************************************************************/
nativeNfcTag_doNdefFormat(JNIEnv * e,jobject o,jbyteArray)1548 static jboolean nativeNfcTag_doNdefFormat(JNIEnv* e, jobject o, jbyteArray) {
1549   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
1550   tNFA_STATUS status = NFA_STATUS_OK;
1551 
1552   // Do not try to format if tag is already deactivated.
1553   if (NfcTag::getInstance().isActivated() == false) {
1554     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1555         "%s: tag already deactivated(no need to format)", __func__);
1556     return JNI_FALSE;
1557   }
1558 
1559   if (0 != sem_init(&sFormatSem, 0, 0)) {
1560     LOG(ERROR) << StringPrintf("%s: semaphore creation failed (errno=0x%08x)",
1561                                __func__, errno);
1562     return JNI_FALSE;
1563   }
1564   sFormatOk = false;
1565   status = NFA_RwFormatTag();
1566   if (status == NFA_STATUS_OK) {
1567     DLOG_IF(INFO, nfc_debug_enabled)
1568         << StringPrintf("%s: wait for completion", __func__);
1569     sem_wait(&sFormatSem);
1570     status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED;
1571   } else
1572     LOG(ERROR) << StringPrintf("%s: error status=%u", __func__, status);
1573   sem_destroy(&sFormatSem);
1574 
1575   if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_ISO_DEP) {
1576     int retCode = NFCSTATUS_SUCCESS;
1577     retCode = nativeNfcTag_doReconnect(e, o);
1578     DLOG_IF(INFO, nfc_debug_enabled)
1579         << StringPrintf("%s Status = 0x%X", __func__, retCode);
1580   }
1581   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
1582   return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
1583 }
1584 
1585 /*******************************************************************************
1586 **
1587 ** Function:        nativeNfcTag_doMakeReadonlyResult
1588 **
1589 ** Description:     Receive the result of making a tag read-only. Called by the
1590 **                  NFA_SET_TAG_RO_EVT.
1591 **                  status: Status of the operation.
1592 **
1593 ** Returns:         None
1594 **
1595 *******************************************************************************/
nativeNfcTag_doMakeReadonlyResult(tNFA_STATUS status)1596 void nativeNfcTag_doMakeReadonlyResult(tNFA_STATUS status) {
1597   if (sMakeReadonlyWaitingForComplete != JNI_FALSE) {
1598     sMakeReadonlyWaitingForComplete = JNI_FALSE;
1599     sMakeReadonlyStatus = status;
1600 
1601     sem_post(&sMakeReadonlySem);
1602   }
1603 }
1604 
1605 /*******************************************************************************
1606 **
1607 ** Function:        nativeNfcTag_doMakeReadonly
1608 **
1609 ** Description:     Make the tag read-only.
1610 **                  e: JVM environment.
1611 **                  o: Java object.
1612 **                  key: Key to access the tag.
1613 **
1614 ** Returns:         True if ok.
1615 **
1616 *******************************************************************************/
nativeNfcTag_doMakeReadonly(JNIEnv * e,jobject o,jbyteArray)1617 static jboolean nativeNfcTag_doMakeReadonly(JNIEnv* e, jobject o, jbyteArray) {
1618   jboolean result = JNI_FALSE;
1619   tNFA_STATUS status;
1620 
1621   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1622 
1623   /* Create the make_readonly semaphore */
1624   if (sem_init(&sMakeReadonlySem, 0, 0) == -1) {
1625     LOG(ERROR) << StringPrintf(
1626         "%s: Make readonly semaphore creation failed (errno=0x%08x)", __func__,
1627         errno);
1628     return JNI_FALSE;
1629   }
1630 
1631   sMakeReadonlyWaitingForComplete = JNI_TRUE;
1632 
1633   // Hard-lock the tag (cannot be reverted)
1634   status = NFA_RwSetTagReadOnly(TRUE);
1635   if (status == NFA_STATUS_REJECTED) {
1636     status = NFA_RwSetTagReadOnly(FALSE);  // try soft lock
1637     if (status != NFA_STATUS_OK) {
1638       LOG(ERROR) << StringPrintf("%s: fail soft lock, status=%d", __func__,
1639                                  status);
1640       goto TheEnd;
1641     }
1642   } else if (status != NFA_STATUS_OK) {
1643     LOG(ERROR) << StringPrintf("%s: fail hard lock, status=%d", __func__,
1644                                status);
1645     goto TheEnd;
1646   }
1647 
1648   /* Wait for check NDEF completion status */
1649   if (sem_wait(&sMakeReadonlySem)) {
1650     LOG(ERROR) << StringPrintf(
1651         "%s: Failed to wait for make_readonly semaphore (errno=0x%08x)",
1652         __func__, errno);
1653     goto TheEnd;
1654   }
1655 
1656   if (sMakeReadonlyStatus == NFA_STATUS_OK) {
1657     result = JNI_TRUE;
1658   }
1659 
1660 TheEnd:
1661   /* Destroy semaphore */
1662   if (sem_destroy(&sMakeReadonlySem)) {
1663     LOG(ERROR) << StringPrintf(
1664         "%s: Failed to destroy read_only semaphore (errno=0x%08x)", __func__,
1665         errno);
1666   }
1667   sMakeReadonlyWaitingForComplete = JNI_FALSE;
1668   return result;
1669 }
1670 
1671 /*******************************************************************************
1672 **
1673 ** Function:        nativeNfcTag_registerNdefTypeHandler
1674 **
1675 ** Description:     Register a callback to receive NDEF message from the tag
1676 **                  from the NFA_NDEF_DATA_EVT.
1677 **
1678 ** Returns:         None
1679 **
1680 *******************************************************************************/
1681 // register a callback to receive NDEF message from the tag
1682 // from the NFA_NDEF_DATA_EVT;
nativeNfcTag_registerNdefTypeHandler()1683 void nativeNfcTag_registerNdefTypeHandler() {
1684   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1685   sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
1686   NFA_RegisterNDefTypeHandler(TRUE, NFA_TNF_DEFAULT, (uint8_t*)"", 0,
1687                               ndefHandlerCallback);
1688 }
1689 
1690 /*******************************************************************************
1691 **
1692 ** Function:        nativeNfcTag_deregisterNdefTypeHandler
1693 **
1694 ** Description:     No longer need to receive NDEF message from the tag.
1695 **
1696 ** Returns:         None
1697 **
1698 *******************************************************************************/
nativeNfcTag_deregisterNdefTypeHandler()1699 void nativeNfcTag_deregisterNdefTypeHandler() {
1700   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1701   NFA_DeregisterNDefTypeHandler(sNdefTypeHandlerHandle);
1702   sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
1703 }
1704 
1705 /*******************************************************************************
1706 **
1707 ** Function:        nativeNfcTag_acquireRfInterfaceMutexLock
1708 **
1709 ** Description:     acquire sRfInterfaceMutex
1710 **
1711 ** Returns:         None
1712 **
1713 *******************************************************************************/
nativeNfcTag_acquireRfInterfaceMutexLock()1714 void nativeNfcTag_acquireRfInterfaceMutexLock() {
1715   DLOG_IF(INFO, nfc_debug_enabled)
1716       << StringPrintf("%s: try to acquire lock", __func__);
1717   sRfInterfaceMutex.lock();
1718   DLOG_IF(INFO, nfc_debug_enabled)
1719       << StringPrintf("%s: sRfInterfaceMutex lock", __func__);
1720 }
1721 
1722 /*******************************************************************************
1723 **
1724 ** Function:       nativeNfcTag_releaseRfInterfaceMutexLock
1725 **
1726 ** Description:    release the sRfInterfaceMutex
1727 **
1728 ** Returns:        None
1729 **
1730 *******************************************************************************/
nativeNfcTag_releaseRfInterfaceMutexLock()1731 void nativeNfcTag_releaseRfInterfaceMutexLock() {
1732   sRfInterfaceMutex.unlock();
1733   DLOG_IF(INFO, nfc_debug_enabled)
1734       << StringPrintf("%s: sRfInterfaceMutex unlock", __func__);
1735 }
1736 
1737 /*****************************************************************************
1738 **
1739 ** JNI functions for Android 4.0.3
1740 **
1741 *****************************************************************************/
1742 static JNINativeMethod gMethods[] = {
1743     {"doConnect", "(I)I", (void*)nativeNfcTag_doConnect},
1744     {"doDisconnect", "()Z", (void*)nativeNfcTag_doDisconnect},
1745     {"doReconnect", "()I", (void*)nativeNfcTag_doReconnect},
1746     {"doHandleReconnect", "(I)I", (void*)nativeNfcTag_doHandleReconnect},
1747     {"doTransceive", "([BZ[I)[B", (void*)nativeNfcTag_doTransceive},
1748     {"doGetNdefType", "(II)I", (void*)nativeNfcTag_doGetNdefType},
1749     {"doCheckNdef", "([I)I", (void*)nativeNfcTag_doCheckNdef},
1750     {"doRead", "()[B", (void*)nativeNfcTag_doRead},
1751     {"doWrite", "([B)Z", (void*)nativeNfcTag_doWrite},
1752     {"doPresenceCheck", "()Z", (void*)nativeNfcTag_doPresenceCheck},
1753     {"doIsIsoDepNdefFormatable", "([B[B)Z",
1754      (void*)nativeNfcTag_doIsIsoDepNdefFormatable},
1755     {"doNdefFormat", "([B)Z", (void*)nativeNfcTag_doNdefFormat},
1756     {"doMakeReadonly", "([B)Z", (void*)nativeNfcTag_doMakeReadonly},
1757 };
1758 
1759 /*******************************************************************************
1760 **
1761 ** Function:        register_com_android_nfc_NativeNfcTag
1762 **
1763 ** Description:     Regisgter JNI functions with Java Virtual Machine.
1764 **                  e: Environment of JVM.
1765 **
1766 ** Returns:         Status of registration.
1767 **
1768 *******************************************************************************/
register_com_android_nfc_NativeNfcTag(JNIEnv * e)1769 int register_com_android_nfc_NativeNfcTag(JNIEnv* e) {
1770   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1771   return jniRegisterNativeMethods(e, gNativeNfcTagClassName, gMethods,
1772                                   NELEM(gMethods));
1773 }
1774 
1775 } /* namespace android */
1776