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 <string.h>
     25 #include "JavaClassConstants.h"
     26 #include "NfcJniUtil.h"
     27 #include "nfa_api.h"
     28 #include "nfa_p2p_api.h"
     29 
     30 using android::base::StringPrintf;
     31 
     32 extern bool nfc_debug_enabled;
     33 
     34 namespace android {
     35 
     36 /*****************************************************************************
     37 **
     38 ** private variables and functions
     39 **
     40 *****************************************************************************/
     41 static sem_t sConnlessRecvSem;
     42 static jboolean sConnlessRecvWaitingForData = JNI_FALSE;
     43 static uint8_t* sConnlessRecvBuf = NULL;
     44 static uint32_t sConnlessRecvLen = 0;
     45 static uint32_t sConnlessRecvRemoteSap = 0;
     46 
     47 /*******************************************************************************
     48 **
     49 ** Function:        nativeLlcpConnectionlessSocket_doSendTo
     50 **
     51 ** Description:     Send data to peer.
     52 **                  e: JVM environment.
     53 **                  o: Java object.
     54 **                  nsap: service access point.
     55 **                  data: buffer for data.
     56 **
     57 ** Returns:         True if ok.
     58 **
     59 *******************************************************************************/
     60 static jboolean nativeLlcpConnectionlessSocket_doSendTo(JNIEnv* e, jobject o,
     61                                                         jint nsap,
     62                                                         jbyteArray data) {
     63   DLOG_IF(INFO, nfc_debug_enabled)
     64       << StringPrintf("%s: nsap = %d", __func__, nsap);
     65 
     66   ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
     67   jfieldID f = e->GetFieldID(c.get(), "mHandle", "I");
     68   jint handle = e->GetIntField(o, f);
     69 
     70   ScopedByteArrayRO bytes(e, data);
     71   if (bytes.get() == NULL) {
     72     return JNI_FALSE;
     73   }
     74   size_t byte_count = bytes.size();
     75 
     76   DLOG_IF(INFO, nfc_debug_enabled)
     77       << StringPrintf("NFA_P2pSendUI: len = %zu", byte_count);
     78   uint8_t* raw_ptr = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(
     79       &bytes[0]));  // TODO: API bug; NFA_P2pSendUI should take const*!
     80   tNFA_STATUS status =
     81       NFA_P2pSendUI((tNFA_HANDLE)handle, nsap, byte_count, raw_ptr);
     82 
     83   DLOG_IF(INFO, nfc_debug_enabled)
     84       << StringPrintf("%s: NFA_P2pSendUI done, status = %d", __func__, status);
     85   if (status != NFA_STATUS_OK) {
     86     LOG(ERROR) << StringPrintf("%s: NFA_P2pSendUI failed, status = %d",
     87                                __func__, status);
     88     return JNI_FALSE;
     89   }
     90   return JNI_TRUE;
     91 }
     92 
     93 /*******************************************************************************
     94 **
     95 ** Function:        nativeLlcpConnectionlessSocket_receiveData
     96 **
     97 ** Description:     Receive data from the stack.
     98 **                  data: buffer contains data.
     99 **                  len: length of data.
    100 **                  remoteSap: remote service access point.
    101 **
    102 ** Returns:         None
    103 **
    104 *******************************************************************************/
    105 void nativeLlcpConnectionlessSocket_receiveData(uint8_t* data, uint32_t len,
    106                                                 uint32_t remoteSap) {
    107   DLOG_IF(INFO, nfc_debug_enabled)
    108       << StringPrintf("%s: waiting for data = %d, len = %d", __func__,
    109                       sConnlessRecvWaitingForData, len);
    110 
    111   // Sanity...
    112   if (sConnlessRecvLen < len) {
    113     len = sConnlessRecvLen;
    114   }
    115 
    116   if (sConnlessRecvWaitingForData) {
    117     sConnlessRecvWaitingForData = JNI_FALSE;
    118     sConnlessRecvLen = len;
    119     memcpy(sConnlessRecvBuf, data, len);
    120     sConnlessRecvRemoteSap = remoteSap;
    121 
    122     sem_post(&sConnlessRecvSem);
    123   }
    124 }
    125 
    126 /*******************************************************************************
    127 **
    128 ** Function:        connectionlessCleanup
    129 **
    130 ** Description:     Free resources.
    131 **
    132 ** Returns:         None
    133 **
    134 *******************************************************************************/
    135 static jobject connectionlessCleanup() {
    136   sConnlessRecvWaitingForData = JNI_FALSE;
    137   sConnlessRecvLen = 0;
    138   if (sConnlessRecvBuf != NULL) {
    139     free(sConnlessRecvBuf);
    140     sConnlessRecvBuf = NULL;
    141   }
    142   return NULL;
    143 }
    144 
    145 /*******************************************************************************
    146 **
    147 ** Function:        nativeLlcpConnectionlessSocket_abortWait
    148 **
    149 ** Description:     Abort current operation and unblock threads.
    150 **
    151 ** Returns:         None
    152 **
    153 *******************************************************************************/
    154 void nativeLlcpConnectionlessSocket_abortWait() { sem_post(&sConnlessRecvSem); }
    155 
    156 /*******************************************************************************
    157 **
    158 ** Function:        nativeLlcpConnectionlessSocket_doReceiveFrom
    159 **
    160 ** Description:     Receive data from a peer.
    161 **                  e: JVM environment.
    162 **                  o: Java object.
    163 **                  linkMiu: max info unit
    164 **
    165 ** Returns:         LlcpPacket Java object.
    166 **
    167 *******************************************************************************/
    168 static jobject nativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv* e, jobject,
    169                                                             jint linkMiu) {
    170   DLOG_IF(INFO, nfc_debug_enabled)
    171       << StringPrintf("%s: linkMiu = %d", __func__, linkMiu);
    172   jobject llcpPacket = NULL;
    173   ScopedLocalRef<jclass> clsLlcpPacket(e, NULL);
    174 
    175   if (sConnlessRecvWaitingForData != JNI_FALSE) {
    176     DLOG_IF(INFO, nfc_debug_enabled)
    177         << StringPrintf("%s: Already waiting for incoming data", __func__);
    178     return NULL;
    179   }
    180 
    181   sConnlessRecvBuf = (uint8_t*)malloc(linkMiu);
    182   if (sConnlessRecvBuf == NULL) {
    183     DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
    184         "%s: Failed to allocate %d bytes memory buffer", __func__, linkMiu);
    185     return NULL;
    186   }
    187   sConnlessRecvLen = linkMiu;
    188 
    189   // Create the write semaphore
    190   if (sem_init(&sConnlessRecvSem, 0, 0) == -1) {
    191     LOG(ERROR) << StringPrintf("%s: semaphore creation failed (errno=0x%08x)",
    192                                __func__, errno);
    193     return connectionlessCleanup();
    194   }
    195 
    196   sConnlessRecvWaitingForData = JNI_TRUE;
    197 
    198   // Wait for sConnlessRecvSem completion status
    199   if (sem_wait(&sConnlessRecvSem)) {
    200     LOG(ERROR) << StringPrintf(
    201         "%s: Failed to wait for write semaphore (errno=0x%08x)", __func__,
    202         errno);
    203     goto TheEnd;
    204   }
    205 
    206   // Create new LlcpPacket object
    207   if (nfc_jni_cache_object_local(e, "com/android/nfc/LlcpPacket",
    208                                  &(llcpPacket)) == -1) {
    209     LOG(ERROR) << StringPrintf("%s: Find LlcpPacket class error", __func__);
    210     return connectionlessCleanup();
    211   }
    212 
    213   // Get NativeConnectionless class object
    214   clsLlcpPacket.reset(e->GetObjectClass(llcpPacket));
    215   if (e->ExceptionCheck()) {
    216     e->ExceptionClear();
    217     LOG(ERROR) << StringPrintf("%s: Get Object class error", __func__);
    218     return connectionlessCleanup();
    219   }
    220 
    221   // Set Llcp Packet remote SAP
    222   jfieldID f;
    223   f = e->GetFieldID(clsLlcpPacket.get(), "mRemoteSap", "I");
    224   e->SetIntField(llcpPacket, f, (jbyte)sConnlessRecvRemoteSap);
    225 
    226   // Set Llcp Packet Buffer
    227   DLOG_IF(INFO, nfc_debug_enabled)
    228       << StringPrintf("%s: Received Llcp packet buffer size = %d\n", __func__,
    229                       sConnlessRecvLen);
    230   f = e->GetFieldID(clsLlcpPacket.get(), "mDataBuffer", "[B");
    231 
    232   {
    233     ScopedLocalRef<jbyteArray> receivedData(e,
    234                                             e->NewByteArray(sConnlessRecvLen));
    235     e->SetByteArrayRegion(receivedData.get(), 0, sConnlessRecvLen,
    236                           (jbyte*)sConnlessRecvBuf);
    237     e->SetObjectField(llcpPacket, f, receivedData.get());
    238   }
    239 
    240 TheEnd:  // TODO: should all the "return connectionlessCleanup()"s in this
    241          // function jump here instead?
    242   connectionlessCleanup();
    243   if (sem_destroy(&sConnlessRecvSem)) {
    244     LOG(ERROR) << StringPrintf(
    245         "%s: Failed to destroy sConnlessRecvSem semaphore (errno=0x%08x)",
    246         __func__, errno);
    247   }
    248   return llcpPacket;
    249 }
    250 
    251 /*******************************************************************************
    252 **
    253 ** Function:        nativeLlcpConnectionlessSocket_doClose
    254 **
    255 ** Description:     Close socket.
    256 **                  e: JVM environment.
    257 **                  o: Java object.
    258 **
    259 ** Returns:         True if ok.
    260 **
    261 *******************************************************************************/
    262 static jboolean nativeLlcpConnectionlessSocket_doClose(JNIEnv* e, jobject o) {
    263   DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s", __func__);
    264 
    265   ScopedLocalRef<jclass> c(e, e->GetObjectClass(o));
    266   jfieldID f = e->GetFieldID(c.get(), "mHandle", "I");
    267   jint handle = e->GetIntField(o, f);
    268 
    269   tNFA_STATUS status = NFA_P2pDisconnect((tNFA_HANDLE)handle, FALSE);
    270   if (status != NFA_STATUS_OK) {
    271     LOG(ERROR) << StringPrintf("%s: disconnect failed, status = %d", __func__,
    272                                status);
    273     return JNI_FALSE;
    274   }
    275   return JNI_TRUE;
    276 }
    277 
    278 /*****************************************************************************
    279 **
    280 ** Description:     JNI functions
    281 **
    282 *****************************************************************************/
    283 static JNINativeMethod gMethods[] = {
    284     {"doSendTo", "(I[B)Z", (void*)nativeLlcpConnectionlessSocket_doSendTo},
    285     {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;",
    286      (void*)nativeLlcpConnectionlessSocket_doReceiveFrom},
    287     {"doClose", "()Z", (void*)nativeLlcpConnectionlessSocket_doClose},
    288 };
    289 
    290 /*******************************************************************************
    291 **
    292 ** Function:        register_com_android_nfc_NativeLlcpConnectionlessSocket
    293 **
    294 ** Description:     Regisgter JNI functions with Java Virtual Machine.
    295 **                  e: Environment of JVM.
    296 **
    297 ** Returns:         Status of registration.
    298 **
    299 *******************************************************************************/
    300 int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv* e) {
    301   return jniRegisterNativeMethods(e, gNativeLlcpConnectionlessSocketClassName,
    302                                   gMethods, NELEM(gMethods));
    303 }
    304 
    305 }  // namespace android
    306