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