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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 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 *******************************************************************************/ 300 int register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv* e) { 301 return jniRegisterNativeMethods(e, gNativeLlcpConnectionlessSocketClassName, 302 gMethods, NELEM(gMethods)); 303 } 304 305 } // namespace android 306