Home | History | Annotate | Download | only in jni
      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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 *******************************************************************************/
    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 
    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 *******************************************************************************/
    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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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;
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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 *******************************************************************************/
   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