• 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 #include "Pn544Interop.h"
34 
35 #include "ndef_utils.h"
36 #include "nfa_api.h"
37 #include "nfa_rw_api.h"
38 #include "nfc_brcm_defs.h"
39 #include "phNxpExtns.h"
40 #include "rw_api.h"
41 
42 using android::base::StringPrintf;
43 
44 namespace android {
45 extern nfc_jni_native_data* getNative(JNIEnv* e, jobject o);
46 extern bool nfcManager_isNfcActive();
47 }  // namespace android
48 
49 extern bool gActivated;
50 extern SyncEvent gDeactivatedEvent;
51 extern bool nfc_debug_enabled;
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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         if (EXTNS_CheckMfcResponse(&transData, &transDataLen) ==
974             NFCSTATUS_FAILED) {
975           nativeNfcTag_doReconnect(e, o);
976         }
977         if (transDataLen != 0) {
978           result.reset(e->NewByteArray(transDataLen));
979           if (result.get() != NULL) {
980             e->SetByteArrayRegion(result.get(), 0, transDataLen,
981                                   (const jbyte*)transData);
982           } else
983             LOG(ERROR) << StringPrintf("%s: Failed to allocate java byte array",
984                                        __func__);
985         }
986       } else {
987         // marshall data to java for return
988         result.reset(e->NewByteArray(sRxDataBuffer.size()));
989         if (result.get() != NULL) {
990           e->SetByteArrayRegion(result.get(), 0, sRxDataBuffer.size(),
991                                 (const jbyte*)sRxDataBuffer.data());
992         } else
993           LOG(ERROR) << StringPrintf("%s: Failed to allocate java byte array",
994                                      __func__);
995       }  // else a nack is treated as a transceive failure to the upper layers
996 
997       sRxDataBuffer.clear();
998     }
999   } while (0);
1000 
1001   sWaitingForTransceive = false;
1002   if (targetLost) e->ReleaseIntArrayElements(statusTargetLost, targetLost, 0);
1003 
1004   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
1005   return result.release();
1006 }
1007 
1008 /*******************************************************************************
1009 **
1010 ** Function:        nativeNfcTag_doGetNdefType
1011 **
1012 ** Description:     Retrieve the type of tag.
1013 **                  e: JVM environment.
1014 **                  o: Java object.
1015 **                  libnfcType: Type of tag represented by JNI.
1016 **                  javaType: Not used.
1017 **
1018 ** Returns:         Type of tag represented by NFC Service.
1019 **
1020 *******************************************************************************/
nativeNfcTag_doGetNdefType(JNIEnv *,jobject,jint libnfcType,jint javaType)1021 static jint nativeNfcTag_doGetNdefType(JNIEnv*, jobject, jint libnfcType,
1022                                        jint javaType) {
1023   DLOG_IF(INFO, nfc_debug_enabled)
1024       << StringPrintf("%s: enter; libnfc type=%d; java type=%d", __func__,
1025                       libnfcType, javaType);
1026   jint ndefType = NDEF_UNKNOWN_TYPE;
1027 
1028   // For NFA, libnfcType is mapped to the protocol value received
1029   // in the NFA_ACTIVATED_EVT and NFA_DISC_RESULT_EVT event.
1030   if (NFA_PROTOCOL_T1T == libnfcType) {
1031     ndefType = NDEF_TYPE1_TAG;
1032   } else if (NFA_PROTOCOL_T2T == libnfcType) {
1033     ndefType = NDEF_TYPE2_TAG;
1034   } else if (NFA_PROTOCOL_T3T == libnfcType) {
1035     ndefType = NDEF_TYPE3_TAG;
1036   } else if (NFA_PROTOCOL_ISO_DEP == libnfcType) {
1037     ndefType = NDEF_TYPE4_TAG;
1038   } else if (NFC_PROTOCOL_MIFARE == libnfcType) {
1039     ndefType = NDEF_MIFARE_CLASSIC_TAG;
1040   } else {
1041     /* NFA_PROTOCOL_T5T, NFA_PROTOCOL_INVALID and others */
1042     ndefType = NDEF_UNKNOWN_TYPE;
1043   }
1044   DLOG_IF(INFO, nfc_debug_enabled)
1045       << StringPrintf("%s: exit; ndef type=%d", __func__, ndefType);
1046   return ndefType;
1047 }
1048 
1049 /*******************************************************************************
1050 **
1051 ** Function:        nativeNfcTag_doCheckNdefResult
1052 **
1053 ** Description:     Receive the result of checking whether the tag contains a
1054 *NDEF
1055 **                  message.  Called by the NFA_NDEF_DETECT_EVT.
1056 **                  status: Status of the operation.
1057 **                  maxSize: Maximum size of NDEF message.
1058 **                  currentSize: Current size of NDEF message.
1059 **                  flags: Indicate various states.
1060 **
1061 ** Returns:         None
1062 **
1063 *******************************************************************************/
nativeNfcTag_doCheckNdefResult(tNFA_STATUS status,uint32_t maxSize,uint32_t currentSize,uint8_t flags)1064 void nativeNfcTag_doCheckNdefResult(tNFA_STATUS status, uint32_t maxSize,
1065                                     uint32_t currentSize, uint8_t flags) {
1066   // this function's flags parameter is defined using the following macros
1067   // in nfc/include/rw_api.h;
1068   //#define RW_NDEF_FL_READ_ONLY  0x01    /* Tag is read only              */
1069   //#define RW_NDEF_FL_FORMATED   0x02    /* Tag formated for NDEF         */
1070   //#define RW_NDEF_FL_SUPPORTED  0x04    /* NDEF supported by the tag     */
1071   //#define RW_NDEF_FL_UNKNOWN    0x08    /* Unable to find if tag is ndef
1072   // capable/formated/read only */ #define RW_NDEF_FL_FORMATABLE 0x10    /* Tag
1073   // supports format operation */
1074 
1075   if (!sCheckNdefWaitingForComplete) {
1076     LOG(ERROR) << StringPrintf("%s: not waiting", __func__);
1077     return;
1078   }
1079 
1080   if (flags & RW_NDEF_FL_READ_ONLY)
1081     DLOG_IF(INFO, nfc_debug_enabled)
1082         << StringPrintf("%s: flag read-only", __func__);
1083   if (flags & RW_NDEF_FL_FORMATED)
1084     DLOG_IF(INFO, nfc_debug_enabled)
1085         << StringPrintf("%s: flag formatted for ndef", __func__);
1086   if (flags & RW_NDEF_FL_SUPPORTED)
1087     DLOG_IF(INFO, nfc_debug_enabled)
1088         << StringPrintf("%s: flag ndef supported", __func__);
1089   if (flags & RW_NDEF_FL_UNKNOWN)
1090     DLOG_IF(INFO, nfc_debug_enabled)
1091         << StringPrintf("%s: flag all unknown", __func__);
1092   if (flags & RW_NDEF_FL_FORMATABLE)
1093     DLOG_IF(INFO, nfc_debug_enabled)
1094         << StringPrintf("%s: flag formattable", __func__);
1095 
1096   sCheckNdefWaitingForComplete = JNI_FALSE;
1097   sCheckNdefStatus = status;
1098   if (sCheckNdefStatus != NFA_STATUS_OK &&
1099       sCheckNdefStatus != NFA_STATUS_TIMEOUT)
1100     sCheckNdefStatus = NFA_STATUS_FAILED;
1101   sCheckNdefCapable = false;  // assume tag is NOT ndef capable
1102   if (sCheckNdefStatus == NFA_STATUS_OK) {
1103     // NDEF content is on the tag
1104     sCheckNdefMaxSize = maxSize;
1105     sCheckNdefCurrentSize = currentSize;
1106     sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
1107     sCheckNdefCapable = true;
1108   } else if (sCheckNdefStatus == NFA_STATUS_FAILED) {
1109     // no NDEF content on the tag
1110     sCheckNdefMaxSize = 0;
1111     sCheckNdefCurrentSize = 0;
1112     sCheckNdefCardReadOnly = flags & RW_NDEF_FL_READ_ONLY;
1113     if ((flags & RW_NDEF_FL_UNKNOWN) == 0)  // if stack understands the tag
1114     {
1115       if (flags & RW_NDEF_FL_SUPPORTED)  // if tag is ndef capable
1116         sCheckNdefCapable = true;
1117     }
1118   } else {
1119     LOG(ERROR) << StringPrintf("%s: unknown status=0x%X", __func__, status);
1120     sCheckNdefMaxSize = 0;
1121     sCheckNdefCurrentSize = 0;
1122     sCheckNdefCardReadOnly = false;
1123   }
1124   sem_post(&sCheckNdefSem);
1125 }
1126 
1127 /*******************************************************************************
1128 **
1129 ** Function:        nativeNfcTag_doCheckNdef
1130 **
1131 ** Description:     Does the tag contain a NDEF message?
1132 **                  e: JVM environment.
1133 **                  o: Java object.
1134 **                  ndefInfo: NDEF info.
1135 **
1136 ** Returns:         Status code; 0 is success.
1137 **
1138 *******************************************************************************/
nativeNfcTag_doCheckNdef(JNIEnv * e,jobject o,jintArray ndefInfo)1139 static jint nativeNfcTag_doCheckNdef(JNIEnv* e, jobject o, jintArray ndefInfo) {
1140   tNFA_STATUS status = NFA_STATUS_FAILED;
1141   jint* ndef = NULL;
1142 
1143   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
1144 
1145   // special case for Kovio
1146   if (sCurrentConnectedTargetProtocol == TARGET_TYPE_KOVIO_BARCODE) {
1147     DLOG_IF(INFO, nfc_debug_enabled)
1148         << StringPrintf("%s: Kovio tag, no NDEF", __func__);
1149     ndef = e->GetIntArrayElements(ndefInfo, 0);
1150     ndef[0] = 0;
1151     ndef[1] = NDEF_MODE_READ_ONLY;
1152     e->ReleaseIntArrayElements(ndefInfo, ndef, 0);
1153     return NFA_STATUS_FAILED;
1154   } else if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1155     nativeNfcTag_doReconnect(e, o);
1156   }
1157 
1158   /* Create the write semaphore */
1159   if (sem_init(&sCheckNdefSem, 0, 0) == -1) {
1160     LOG(ERROR) << StringPrintf(
1161         "%s: Check NDEF semaphore creation failed (errno=0x%08x)", __func__,
1162         errno);
1163     return JNI_FALSE;
1164   }
1165 
1166   if (NfcTag::getInstance().getActivationState() != NfcTag::Active) {
1167     LOG(ERROR) << StringPrintf("%s: tag already deactivated", __func__);
1168     goto TheEnd;
1169   }
1170 
1171   DLOG_IF(INFO, nfc_debug_enabled)
1172       << StringPrintf("%s: try NFA_RwDetectNDef", __func__);
1173   sCheckNdefWaitingForComplete = JNI_TRUE;
1174 
1175   if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1176     status = EXTNS_MfcCheckNDef();
1177   } else {
1178     status = NFA_RwDetectNDef();
1179   }
1180 
1181   if (status != NFA_STATUS_OK) {
1182     LOG(ERROR) << StringPrintf("%s: NFA_RwDetectNDef failed, status = 0x%X",
1183                                __func__, status);
1184     goto TheEnd;
1185   }
1186 
1187   /* Wait for check NDEF completion status */
1188   if (sem_wait(&sCheckNdefSem)) {
1189     LOG(ERROR) << StringPrintf(
1190         "%s: Failed to wait for check NDEF semaphore (errno=0x%08x)", __func__,
1191         errno);
1192     goto TheEnd;
1193   }
1194 
1195   if (sCheckNdefStatus == NFA_STATUS_OK) {
1196     // stack found a NDEF message on the tag
1197     ndef = e->GetIntArrayElements(ndefInfo, 0);
1198     if (NfcTag::getInstance().getProtocol() == NFA_PROTOCOL_T1T)
1199       ndef[0] = NfcTag::getInstance().getT1tMaxMessageSize();
1200     else
1201       ndef[0] = sCheckNdefMaxSize;
1202     if (sCheckNdefCardReadOnly)
1203       ndef[1] = NDEF_MODE_READ_ONLY;
1204     else
1205       ndef[1] = NDEF_MODE_READ_WRITE;
1206     e->ReleaseIntArrayElements(ndefInfo, ndef, 0);
1207     status = NFA_STATUS_OK;
1208   } else if (sCheckNdefStatus == NFA_STATUS_FAILED) {
1209     // stack did not find a NDEF message on the tag;
1210     ndef = e->GetIntArrayElements(ndefInfo, 0);
1211     if (NfcTag::getInstance().getProtocol() == NFA_PROTOCOL_T1T)
1212       ndef[0] = NfcTag::getInstance().getT1tMaxMessageSize();
1213     else
1214       ndef[0] = sCheckNdefMaxSize;
1215     if (sCheckNdefCardReadOnly)
1216       ndef[1] = NDEF_MODE_READ_ONLY;
1217     else
1218       ndef[1] = NDEF_MODE_READ_WRITE;
1219     e->ReleaseIntArrayElements(ndefInfo, ndef, 0);
1220     status = NFA_STATUS_FAILED;
1221   } else if ((sCheckNdefStatus == NFA_STATUS_TIMEOUT) &&
1222              (NfcTag::getInstance().getProtocol() == NFC_PROTOCOL_ISO_DEP)) {
1223     pn544InteropStopPolling();
1224     status = sCheckNdefStatus;
1225   } else {
1226     DLOG_IF(INFO, nfc_debug_enabled)
1227         << StringPrintf("%s: unknown status 0x%X", __func__, sCheckNdefStatus);
1228     status = sCheckNdefStatus;
1229   }
1230 
1231   /* Reconnect Mifare Classic Tag for furture use */
1232   if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1233     nativeNfcTag_doReconnect(e, o);
1234   }
1235 
1236 TheEnd:
1237   /* Destroy semaphore */
1238   if (sem_destroy(&sCheckNdefSem)) {
1239     LOG(ERROR) << StringPrintf(
1240         "%s: Failed to destroy check NDEF semaphore (errno=0x%08x)", __func__,
1241         errno);
1242   }
1243   sCheckNdefWaitingForComplete = JNI_FALSE;
1244   DLOG_IF(INFO, nfc_debug_enabled)
1245       << StringPrintf("%s: exit; status=0x%X", __func__, status);
1246   return status;
1247 }
1248 
1249 /*******************************************************************************
1250 **
1251 ** Function:        nativeNfcTag_resetPresenceCheck
1252 **
1253 ** Description:     Reset variables related to presence-check.
1254 **
1255 ** Returns:         None
1256 **
1257 *******************************************************************************/
nativeNfcTag_resetPresenceCheck()1258 void nativeNfcTag_resetPresenceCheck() { sIsTagPresent = true; }
1259 
1260 /*******************************************************************************
1261 **
1262 ** Function:        nativeNfcTag_doPresenceCheckResult
1263 **
1264 ** Description:     Receive the result of presence-check.
1265 **                  status: Result of presence-check.
1266 **
1267 ** Returns:         None
1268 **
1269 *******************************************************************************/
nativeNfcTag_doPresenceCheckResult(tNFA_STATUS status)1270 void nativeNfcTag_doPresenceCheckResult(tNFA_STATUS status) {
1271   SyncEventGuard guard(sPresenceCheckEvent);
1272   sIsTagPresent = status == NFA_STATUS_OK;
1273   sPresenceCheckEvent.notifyOne();
1274 }
1275 
1276 /*******************************************************************************
1277 **
1278 ** Function:        nativeNfcTag_doPresenceCheck
1279 **
1280 ** Description:     Check if the tag is in the RF field.
1281 **                  e: JVM environment.
1282 **                  o: Java object.
1283 **
1284 ** Returns:         True if tag is in RF field.
1285 **
1286 *******************************************************************************/
nativeNfcTag_doPresenceCheck(JNIEnv *,jobject)1287 static jboolean nativeNfcTag_doPresenceCheck(JNIEnv*, jobject) {
1288   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1289   tNFA_STATUS status = NFA_STATUS_OK;
1290   jboolean isPresent = JNI_FALSE;
1291 
1292   // Special case for Kovio.  The deactivation would have already occurred
1293   // but was ignored so that normal tag opertions could complete.  Now we
1294   // want to process as if the deactivate just happened.
1295   if (sCurrentConnectedTargetProtocol == TARGET_TYPE_KOVIO_BARCODE) {
1296     DLOG_IF(INFO, nfc_debug_enabled)
1297         << StringPrintf("%s: Kovio, force deactivate handling", __func__);
1298     tNFA_DEACTIVATED deactivated = {NFA_DEACTIVATE_TYPE_IDLE};
1299     {
1300       SyncEventGuard g(gDeactivatedEvent);
1301       gActivated = false;  // guard this variable from multi-threaded access
1302       gDeactivatedEvent.notifyOne();
1303     }
1304 
1305     NfcTag::getInstance().setDeactivationState(deactivated);
1306     nativeNfcTag_resetPresenceCheck();
1307     NfcTag::getInstance().connectionEventHandler(NFA_DEACTIVATED_EVT, NULL);
1308     nativeNfcTag_abortWaits();
1309     NfcTag::getInstance().abort();
1310 
1311     return JNI_FALSE;
1312   }
1313 
1314   if (nfcManager_isNfcActive() == false) {
1315     DLOG_IF(INFO, nfc_debug_enabled)
1316         << StringPrintf("%s: NFC is no longer active.", __func__);
1317     return JNI_FALSE;
1318   }
1319 
1320   if (!sRfInterfaceMutex.tryLock()) {
1321     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1322         "%s: tag is being reSelected assume it is present", __func__);
1323     return JNI_TRUE;
1324   }
1325 
1326   sRfInterfaceMutex.unlock();
1327 
1328   if (NfcTag::getInstance().isActivated() == false) {
1329     DLOG_IF(INFO, nfc_debug_enabled)
1330         << StringPrintf("%s: tag already deactivated", __func__);
1331     return JNI_FALSE;
1332   }
1333   if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1334     status = EXTNS_MfcPresenceCheck();
1335     if (status == NFCSTATUS_SUCCESS) {
1336       return (NFCSTATUS_SUCCESS == EXTNS_GetPresenceCheckStatus()) ? JNI_TRUE
1337                                                                    : JNI_FALSE;
1338     }
1339   }
1340 
1341   {
1342     SyncEventGuard guard(sPresenceCheckEvent);
1343     status =
1344         NFA_RwPresenceCheck(NfcTag::getInstance().getPresenceCheckAlgorithm());
1345     if (status == NFA_STATUS_OK) {
1346       sPresenceCheckEvent.wait();
1347       isPresent = sIsTagPresent ? JNI_TRUE : JNI_FALSE;
1348     }
1349   }
1350 
1351   if (isPresent == JNI_FALSE)
1352     DLOG_IF(INFO, nfc_debug_enabled)
1353         << StringPrintf("%s: tag absent", __func__);
1354   return isPresent;
1355 }
1356 
1357 /*******************************************************************************
1358 **
1359 ** Function:        nativeNfcTag_doIsNdefFormatable
1360 **
1361 ** Description:     Can tag be formatted to store NDEF message?
1362 **                  e: JVM environment.
1363 **                  o: Java object.
1364 **                  libNfcType: Type of tag.
1365 **                  uidBytes: Tag's unique ID.
1366 **                  pollBytes: Data from activation.
1367 **                  actBytes: Data from activation.
1368 **
1369 ** Returns:         True if formattable.
1370 **
1371 *******************************************************************************/
nativeNfcTag_doIsNdefFormatable(JNIEnv * e,jobject o,jint,jbyteArray,jbyteArray,jbyteArray)1372 static jboolean nativeNfcTag_doIsNdefFormatable(JNIEnv* e, jobject o,
1373                                                 jint /*libNfcType*/, jbyteArray,
1374                                                 jbyteArray, jbyteArray) {
1375   jboolean isFormattable = JNI_FALSE;
1376   tNFC_PROTOCOL protocol = NfcTag::getInstance().getProtocol();
1377   if (NFA_PROTOCOL_T1T == protocol || NFA_PROTOCOL_T5T == protocol ||
1378       NFC_PROTOCOL_MIFARE == protocol) {
1379     isFormattable = JNI_TRUE;
1380   } else if (NFA_PROTOCOL_T3T == protocol) {
1381     isFormattable = NfcTag::getInstance().isFelicaLite() ? JNI_TRUE : JNI_FALSE;
1382   } else if (NFA_PROTOCOL_T2T == protocol) {
1383     isFormattable = (NfcTag::getInstance().isMifareUltralight() |
1384                      NfcTag::getInstance().isInfineonMyDMove() |
1385                      NfcTag::getInstance().isKovioType2Tag())
1386                         ? JNI_TRUE
1387                         : JNI_FALSE;
1388   } else if (NFA_PROTOCOL_ISO_DEP == protocol) {
1389     /**
1390      * Determines whether this is a formatable IsoDep tag - currectly only NXP
1391      * DESFire is supported.
1392      */
1393     uint8_t cmd[] = {0x90, 0x60, 0x00, 0x00, 0x00};
1394 
1395     if (NfcTag::getInstance().isMifareDESFire()) {
1396       /* Identifies as DESfire, use get version cmd to be sure */
1397       jbyteArray versionCmd = e->NewByteArray(5);
1398       e->SetByteArrayRegion(versionCmd, 0, 5, (jbyte*)cmd);
1399       jbyteArray respBytes =
1400           nativeNfcTag_doTransceive(e, o, versionCmd, JNI_TRUE, NULL);
1401       if (respBytes != NULL) {
1402         // Check whether the response matches a typical DESfire
1403         // response.
1404         // libNFC even does more advanced checking than we do
1405         // here, and will only format DESfire's with a certain
1406         // major/minor sw version and NXP as a manufacturer.
1407         // We don't want to do such checking here, to avoid
1408         // having to change code in multiple places.
1409         // A succesful (wrapped) DESFire getVersion command returns
1410         // 9 bytes, with byte 7 0x91 and byte 8 having status
1411         // code 0xAF (these values are fixed and well-known).
1412         int respLength = e->GetArrayLength(respBytes);
1413         uint8_t* resp = (uint8_t*)e->GetByteArrayElements(respBytes, NULL);
1414         if (respLength == 9 && resp[7] == 0x91 && resp[8] == 0xAF) {
1415           isFormattable = JNI_TRUE;
1416         }
1417         e->ReleaseByteArrayElements(respBytes, (jbyte*)resp, JNI_ABORT);
1418       }
1419     }
1420   }
1421 
1422   DLOG_IF(INFO, nfc_debug_enabled)
1423       << StringPrintf("%s: is formattable=%u", __func__, isFormattable);
1424   return isFormattable;
1425 }
1426 
1427 /*******************************************************************************
1428 **
1429 ** Function:        nativeNfcTag_doIsIsoDepNdefFormatable
1430 **
1431 ** Description:     Is ISO-DEP tag formattable?
1432 **                  e: JVM environment.
1433 **                  o: Java object.
1434 **                  pollBytes: Data from activation.
1435 **                  actBytes: Data from activation.
1436 **
1437 ** Returns:         True if formattable.
1438 **
1439 *******************************************************************************/
nativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv * e,jobject o,jbyteArray pollBytes,jbyteArray actBytes)1440 static jboolean nativeNfcTag_doIsIsoDepNdefFormatable(JNIEnv* e, jobject o,
1441                                                       jbyteArray pollBytes,
1442                                                       jbyteArray actBytes) {
1443   uint8_t uidFake[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
1444   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1445   jbyteArray uidArray = e->NewByteArray(8);
1446   e->SetByteArrayRegion(uidArray, 0, 8, (jbyte*)uidFake);
1447   return nativeNfcTag_doIsNdefFormatable(e, o, 0, uidArray, pollBytes,
1448                                          actBytes);
1449 }
1450 
1451 /*******************************************************************************
1452 **
1453 ** Function:        nativeNfcTag_makeMifareNdefFormat
1454 **
1455 ** Description:     Format a mifare classic tag so it can store NDEF message.
1456 **                  e: JVM environment.
1457 **                  o: Java object.
1458 **                  key: Key to acces tag.
1459 **                  keySize: size of Key.
1460 **
1461 ** Returns:         True if ok.
1462 **
1463 *******************************************************************************/
nativeNfcTag_makeMifareNdefFormat(JNIEnv * e,jobject o,uint8_t * key,uint32_t keySize)1464 static jboolean nativeNfcTag_makeMifareNdefFormat(JNIEnv* e, jobject o,
1465                                                   uint8_t* key,
1466                                                   uint32_t keySize) {
1467   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
1468   tNFA_STATUS status = NFA_STATUS_OK;
1469 
1470   status = nativeNfcTag_doReconnect(e, o);
1471   if (status != NFA_STATUS_OK) {
1472     DLOG_IF(INFO, nfc_debug_enabled)
1473         << StringPrintf("%s: reconnect error, status=%u", __func__, status);
1474     return JNI_FALSE;
1475   }
1476 
1477   sem_init(&sFormatSem, 0, 0);
1478   sFormatOk = false;
1479 
1480   status = EXTNS_MfcFormatTag(key, keySize);
1481 
1482   if (status == NFA_STATUS_OK) {
1483     DLOG_IF(INFO, nfc_debug_enabled)
1484         << StringPrintf("%s: wait for completion", __func__);
1485     sem_wait(&sFormatSem);
1486     status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED;
1487   } else {
1488     LOG(ERROR) << StringPrintf("%s: error status=%u", __func__, status);
1489   }
1490 
1491   sem_destroy(&sFormatSem);
1492   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
1493   return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
1494 }
1495 
1496 /*******************************************************************************
1497 **
1498 ** Function:        nativeNfcTag_doNdefFormat
1499 **
1500 ** Description:     Format a tag so it can store NDEF message.
1501 **                  e: JVM environment.
1502 **                  o: Java object.
1503 **                  key: Not used.
1504 **
1505 ** Returns:         True if ok.
1506 **
1507 *******************************************************************************/
nativeNfcTag_doNdefFormat(JNIEnv * e,jobject o,jbyteArray)1508 static jboolean nativeNfcTag_doNdefFormat(JNIEnv* e, jobject o, jbyteArray) {
1509   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", __func__);
1510   tNFA_STATUS status = NFA_STATUS_OK;
1511 
1512   // Do not try to format if tag is already deactivated.
1513   if (NfcTag::getInstance().isActivated() == false) {
1514     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
1515         "%s: tag already deactivated(no need to format)", __func__);
1516     return JNI_FALSE;
1517   }
1518 
1519   if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1520     static uint8_t mfc_key1[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1521     static uint8_t mfc_key2[6] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
1522     jboolean result;
1523 
1524     result =
1525         nativeNfcTag_makeMifareNdefFormat(e, o, mfc_key1, sizeof(mfc_key1));
1526     if (result == JNI_FALSE) {
1527       result =
1528           nativeNfcTag_makeMifareNdefFormat(e, o, mfc_key2, sizeof(mfc_key2));
1529     }
1530     return result;
1531   }
1532 
1533   sem_init(&sFormatSem, 0, 0);
1534   sFormatOk = false;
1535   status = NFA_RwFormatTag();
1536   if (status == NFA_STATUS_OK) {
1537     DLOG_IF(INFO, nfc_debug_enabled)
1538         << StringPrintf("%s: wait for completion", __func__);
1539     sem_wait(&sFormatSem);
1540     status = sFormatOk ? NFA_STATUS_OK : NFA_STATUS_FAILED;
1541   } else
1542     LOG(ERROR) << StringPrintf("%s: error status=%u", __func__, status);
1543   sem_destroy(&sFormatSem);
1544 
1545   if (sCurrentConnectedTargetProtocol == NFA_PROTOCOL_ISO_DEP) {
1546     int retCode = NFCSTATUS_SUCCESS;
1547     retCode = nativeNfcTag_doReconnect(e, o);
1548   }
1549   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", __func__);
1550   return (status == NFA_STATUS_OK) ? JNI_TRUE : JNI_FALSE;
1551 }
1552 
1553 /*******************************************************************************
1554 **
1555 ** Function:        nativeNfcTag_doMakeReadonlyResult
1556 **
1557 ** Description:     Receive the result of making a tag read-only. Called by the
1558 **                  NFA_SET_TAG_RO_EVT.
1559 **                  status: Status of the operation.
1560 **
1561 ** Returns:         None
1562 **
1563 *******************************************************************************/
nativeNfcTag_doMakeReadonlyResult(tNFA_STATUS status)1564 void nativeNfcTag_doMakeReadonlyResult(tNFA_STATUS status) {
1565   if (sMakeReadonlyWaitingForComplete != JNI_FALSE) {
1566     sMakeReadonlyWaitingForComplete = JNI_FALSE;
1567     sMakeReadonlyStatus = status;
1568 
1569     sem_post(&sMakeReadonlySem);
1570   }
1571 }
1572 
1573 /*******************************************************************************
1574 **
1575 ** Function:        nativeNfcTag_makeMifareReadonly
1576 **
1577 ** Description:     Make the mifare classic tag read-only.
1578 **                  e: JVM environment.
1579 **                  o: Java object.
1580 **                  key: Key to access the tag.
1581 **                  keySize: size of Key.
1582 **
1583 ** Returns:         True if ok.
1584 **
1585 *******************************************************************************/
nativeNfcTag_makeMifareReadonly(JNIEnv * e,jobject o,uint8_t * key,int32_t keySize)1586 static jboolean nativeNfcTag_makeMifareReadonly(JNIEnv* e, jobject o,
1587                                                 uint8_t* key, int32_t keySize) {
1588   jboolean result = JNI_FALSE;
1589   tNFA_STATUS status = NFA_STATUS_OK;
1590 
1591   sMakeReadonlyStatus = NFA_STATUS_FAILED;
1592 
1593   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1594 
1595   /* Create the make_readonly semaphore */
1596   if (sem_init(&sMakeReadonlySem, 0, 0) == -1) {
1597     LOG(ERROR) << StringPrintf(
1598         "%s: Make readonly semaphore creation failed (errno=0x%08x)", __func__,
1599         errno);
1600     return JNI_FALSE;
1601   }
1602 
1603   sMakeReadonlyWaitingForComplete = JNI_TRUE;
1604 
1605   status = nativeNfcTag_doReconnect(e, o);
1606   if (status != NFA_STATUS_OK) {
1607     goto TheEnd;
1608   }
1609 
1610   status = EXTNS_MfcSetReadOnly(key, keySize);
1611   if (status != NFA_STATUS_OK) {
1612     goto TheEnd;
1613   }
1614   sem_wait(&sMakeReadonlySem);
1615 
1616   if (sMakeReadonlyStatus == NFA_STATUS_OK) {
1617     result = JNI_TRUE;
1618   }
1619 
1620 TheEnd:
1621   /* Destroy semaphore */
1622   if (sem_destroy(&sMakeReadonlySem)) {
1623     LOG(ERROR) << StringPrintf(
1624         "%s: Failed to destroy read_only semaphore (errno=0x%08x)", __func__,
1625         errno);
1626   }
1627   sMakeReadonlyWaitingForComplete = JNI_FALSE;
1628   return result;
1629 }
1630 
1631 /*******************************************************************************
1632 **
1633 ** Function:        nativeNfcTag_doMakeReadonly
1634 **
1635 ** Description:     Make the tag read-only.
1636 **                  e: JVM environment.
1637 **                  o: Java object.
1638 **                  key: Key to access the tag.
1639 **
1640 ** Returns:         True if ok.
1641 **
1642 *******************************************************************************/
nativeNfcTag_doMakeReadonly(JNIEnv * e,jobject o,jbyteArray)1643 static jboolean nativeNfcTag_doMakeReadonly(JNIEnv* e, jobject o, jbyteArray) {
1644   jboolean result = JNI_FALSE;
1645   tNFA_STATUS status;
1646 
1647   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1648 
1649   if (sCurrentConnectedTargetProtocol == NFC_PROTOCOL_MIFARE) {
1650     static uint8_t mfc_key1[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1651     static uint8_t mfc_key2[6] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
1652     result = nativeNfcTag_makeMifareReadonly(e, o, mfc_key1, sizeof(mfc_key1));
1653     if (result == JNI_FALSE) {
1654       result =
1655           nativeNfcTag_makeMifareReadonly(e, o, mfc_key2, sizeof(mfc_key2));
1656     }
1657     return result;
1658   }
1659 
1660   /* Create the make_readonly semaphore */
1661   if (sem_init(&sMakeReadonlySem, 0, 0) == -1) {
1662     LOG(ERROR) << StringPrintf(
1663         "%s: Make readonly semaphore creation failed (errno=0x%08x)", __func__,
1664         errno);
1665     return JNI_FALSE;
1666   }
1667 
1668   sMakeReadonlyWaitingForComplete = JNI_TRUE;
1669 
1670   // Hard-lock the tag (cannot be reverted)
1671   status = NFA_RwSetTagReadOnly(TRUE);
1672   if (status == NFA_STATUS_REJECTED) {
1673     status = NFA_RwSetTagReadOnly(FALSE);  // try soft lock
1674     if (status != NFA_STATUS_OK) {
1675       LOG(ERROR) << StringPrintf("%s: fail soft lock, status=%d", __func__,
1676                                  status);
1677       goto TheEnd;
1678     }
1679   } else if (status != NFA_STATUS_OK) {
1680     LOG(ERROR) << StringPrintf("%s: fail hard lock, status=%d", __func__,
1681                                status);
1682     goto TheEnd;
1683   }
1684 
1685   /* Wait for check NDEF completion status */
1686   if (sem_wait(&sMakeReadonlySem)) {
1687     LOG(ERROR) << StringPrintf(
1688         "%s: Failed to wait for make_readonly semaphore (errno=0x%08x)",
1689         __func__, errno);
1690     goto TheEnd;
1691   }
1692 
1693   if (sMakeReadonlyStatus == NFA_STATUS_OK) {
1694     result = JNI_TRUE;
1695   }
1696 
1697 TheEnd:
1698   /* Destroy semaphore */
1699   if (sem_destroy(&sMakeReadonlySem)) {
1700     LOG(ERROR) << StringPrintf(
1701         "%s: Failed to destroy read_only semaphore (errno=0x%08x)", __func__,
1702         errno);
1703   }
1704   sMakeReadonlyWaitingForComplete = JNI_FALSE;
1705   return result;
1706 }
1707 
1708 /*******************************************************************************
1709 **
1710 ** Function:        nativeNfcTag_registerNdefTypeHandler
1711 **
1712 ** Description:     Register a callback to receive NDEF message from the tag
1713 **                  from the NFA_NDEF_DATA_EVT.
1714 **
1715 ** Returns:         None
1716 **
1717 *******************************************************************************/
1718 // register a callback to receive NDEF message from the tag
1719 // from the NFA_NDEF_DATA_EVT;
nativeNfcTag_registerNdefTypeHandler()1720 void nativeNfcTag_registerNdefTypeHandler() {
1721   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1722   sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
1723   NFA_RegisterNDefTypeHandler(TRUE, NFA_TNF_DEFAULT, (uint8_t*)"", 0,
1724                               ndefHandlerCallback);
1725   EXTNS_MfcRegisterNDefTypeHandler(ndefHandlerCallback);
1726 }
1727 
1728 /*******************************************************************************
1729 **
1730 ** Function:        nativeNfcTag_deregisterNdefTypeHandler
1731 **
1732 ** Description:     No longer need to receive NDEF message from the tag.
1733 **
1734 ** Returns:         None
1735 **
1736 *******************************************************************************/
nativeNfcTag_deregisterNdefTypeHandler()1737 void nativeNfcTag_deregisterNdefTypeHandler() {
1738   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1739   NFA_DeregisterNDefTypeHandler(sNdefTypeHandlerHandle);
1740   sNdefTypeHandlerHandle = NFA_HANDLE_INVALID;
1741 }
1742 
1743 /*******************************************************************************
1744 **
1745 ** Function:        nativeNfcTag_acquireRfInterfaceMutexLock
1746 **
1747 ** Description:     acquire sRfInterfaceMutex
1748 **
1749 ** Returns:         None
1750 **
1751 *******************************************************************************/
nativeNfcTag_acquireRfInterfaceMutexLock()1752 void nativeNfcTag_acquireRfInterfaceMutexLock() {
1753   DLOG_IF(INFO, nfc_debug_enabled)
1754       << StringPrintf("%s: try to acquire lock", __func__);
1755   sRfInterfaceMutex.lock();
1756   DLOG_IF(INFO, nfc_debug_enabled)
1757       << StringPrintf("%s: sRfInterfaceMutex lock", __func__);
1758 }
1759 
1760 /*******************************************************************************
1761 **
1762 ** Function:       nativeNfcTag_releaseRfInterfaceMutexLock
1763 **
1764 ** Description:    release the sRfInterfaceMutex
1765 **
1766 ** Returns:        None
1767 **
1768 *******************************************************************************/
nativeNfcTag_releaseRfInterfaceMutexLock()1769 void nativeNfcTag_releaseRfInterfaceMutexLock() {
1770   sRfInterfaceMutex.unlock();
1771   DLOG_IF(INFO, nfc_debug_enabled)
1772       << StringPrintf("%s: sRfInterfaceMutex unlock", __func__);
1773 }
1774 
1775 /*****************************************************************************
1776 **
1777 ** JNI functions for Android 4.0.3
1778 **
1779 *****************************************************************************/
1780 static JNINativeMethod gMethods[] = {
1781     {"doConnect", "(I)I", (void*)nativeNfcTag_doConnect},
1782     {"doDisconnect", "()Z", (void*)nativeNfcTag_doDisconnect},
1783     {"doReconnect", "()I", (void*)nativeNfcTag_doReconnect},
1784     {"doHandleReconnect", "(I)I", (void*)nativeNfcTag_doHandleReconnect},
1785     {"doTransceive", "([BZ[I)[B", (void*)nativeNfcTag_doTransceive},
1786     {"doGetNdefType", "(II)I", (void*)nativeNfcTag_doGetNdefType},
1787     {"doCheckNdef", "([I)I", (void*)nativeNfcTag_doCheckNdef},
1788     {"doRead", "()[B", (void*)nativeNfcTag_doRead},
1789     {"doWrite", "([B)Z", (void*)nativeNfcTag_doWrite},
1790     {"doPresenceCheck", "()Z", (void*)nativeNfcTag_doPresenceCheck},
1791     {"doIsIsoDepNdefFormatable", "([B[B)Z",
1792      (void*)nativeNfcTag_doIsIsoDepNdefFormatable},
1793     {"doNdefFormat", "([B)Z", (void*)nativeNfcTag_doNdefFormat},
1794     {"doMakeReadonly", "([B)Z", (void*)nativeNfcTag_doMakeReadonly},
1795 };
1796 
1797 /*******************************************************************************
1798 **
1799 ** Function:        register_com_android_nfc_NativeNfcTag
1800 **
1801 ** Description:     Regisgter JNI functions with Java Virtual Machine.
1802 **                  e: Environment of JVM.
1803 **
1804 ** Returns:         Status of registration.
1805 **
1806 *******************************************************************************/
register_com_android_nfc_NativeNfcTag(JNIEnv * e)1807 int register_com_android_nfc_NativeNfcTag(JNIEnv* e) {
1808   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
1809   return jniRegisterNativeMethods(e, gNativeNfcTagClassName, gMethods,
1810                                   NELEM(gMethods));
1811 }
1812 
1813 } /* namespace android */
1814