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