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 *******************************************************************************/
nativeLlcpConnectionlessSocket_doSendTo(JNIEnv * e,jobject o,jint nsap,jbyteArray data)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 *******************************************************************************/
nativeLlcpConnectionlessSocket_receiveData(uint8_t * data,uint32_t len,uint32_t remoteSap)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 *******************************************************************************/
connectionlessCleanup()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 *******************************************************************************/
nativeLlcpConnectionlessSocket_abortWait()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 *******************************************************************************/
nativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv * e,jobject,jint linkMiu)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 *******************************************************************************/
nativeLlcpConnectionlessSocket_doClose(JNIEnv * e,jobject o)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 *******************************************************************************/
register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv * e)300 int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv* e) {
301 return jniRegisterNativeMethods(e, gNativeLlcpConnectionlessSocketClassName,
302 gMethods, NELEM(gMethods));
303 }
304
305 } // namespace android
306