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