• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *******************************************************************************/
nativeLlcpConnectionlessSocket_doSendTo(JNIEnv * e,jobject o,jint nsap,jbyteArray data)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 *******************************************************************************/
nativeLlcpConnectionlessSocket_receiveData(uint8_t * data,uint32_t len,uint32_t remoteSap)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 *******************************************************************************/
connectionlessCleanup()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 *******************************************************************************/
nativeLlcpConnectionlessSocket_abortWait()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 *******************************************************************************/
nativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv * e,jobject,jint linkMiu)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 (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 *******************************************************************************/
nativeLlcpConnectionlessSocket_doClose(JNIEnv * e,jobject o)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 *******************************************************************************/
register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv * e)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