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