| /* |
| * Copyright (C) 2006 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "JNIHelp" |
| |
| #include "JNIHelp.h" |
| |
| #include "log_compat.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <assert.h> |
| |
| /** |
| * Equivalent to ScopedLocalRef, but for C_JNIEnv instead. (And slightly more powerful.) |
| */ |
| template<typename T> |
| class scoped_local_ref { |
| public: |
| scoped_local_ref(JNIEnv* env, T localRef = NULL) |
| : mEnv(env), mLocalRef(localRef) |
| { |
| } |
| |
| ~scoped_local_ref() { |
| reset(); |
| } |
| |
| void reset(T localRef = NULL) { |
| if (mLocalRef != NULL) { |
| mEnv->DeleteLocalRef(mLocalRef); |
| mLocalRef = localRef; |
| } |
| } |
| |
| T get() const { |
| return mLocalRef; |
| } |
| |
| private: |
| JNIEnv* mEnv; |
| T mLocalRef; |
| |
| // Disallow copy and assignment. |
| scoped_local_ref(const scoped_local_ref&); |
| void operator=(const scoped_local_ref&); |
| }; |
| |
| static jclass findClass(JNIEnv* env, const char* className) { |
| return env->FindClass(className); |
| } |
| |
| extern "C" int jniRegisterNativeMethods(JNIEnv* env, const char* className, |
| const JNINativeMethod* gMethods, int numMethods) |
| { |
| ALOGV("Registering %s's %d native methods...", className, numMethods); |
| |
| scoped_local_ref<jclass> c(env, findClass(env, className)); |
| if (c.get() == NULL) { |
| char* msg; |
| asprintf(&msg, "Native registration unable to find class '%s'; aborting...", className); |
| env->FatalError(msg); |
| } |
| |
| if (env->RegisterNatives(c.get(), gMethods, numMethods) < 0) { |
| char* msg; |
| asprintf(&msg, "RegisterNatives failed for '%s'; aborting...", className); |
| env->FatalError(msg); |
| } |
| |
| return 0; |
| } |
| |
| #ifdef __cplusplus |
| extern "C" |
| #endif |
| int jniThrowException(JNIEnv* env, const char* className, const char* msg) { |
| jclass exceptionClass = env->FindClass(className); |
| |
| if (exceptionClass == NULL) { |
| ALOGD("Unable to find exception class %s", className); |
| /* ClassNotFoundException now pending */ |
| return -1; |
| } |
| |
| if (env->ThrowNew(exceptionClass, msg) != JNI_OK) { |
| ALOGD("Failed throwing '%s' '%s'", className, msg); |
| /* an exception, most likely OOM, will now be pending */ |
| return -1; |
| } |
| |
| env->DeleteLocalRef(exceptionClass); |
| return 0; |
| } |
| |
| int jniThrowExceptionFmt(JNIEnv* env, const char* className, const char* fmt, va_list args) { |
| char msgBuf[512]; |
| vsnprintf(msgBuf, sizeof(msgBuf), fmt, args); |
| return jniThrowException(env, className, msgBuf); |
| } |
| |
| int jniThrowNullPointerException(JNIEnv* env, const char* msg) { |
| return jniThrowException(env, "java/lang/NullPointerException", msg); |
| } |
| |
| int jniThrowRuntimeException(JNIEnv* env, const char* msg) { |
| return jniThrowException(env, "java/lang/RuntimeException", msg); |
| } |
| |
| int jniThrowIOException(JNIEnv* env, int errnum) { |
| char buffer[80]; |
| const char* message = jniStrError(errnum, buffer, sizeof(buffer)); |
| return jniThrowException(env, "java/io/IOException", message); |
| } |
| |
| const char* jniStrError(int errnum, char* buf, size_t buflen) { |
| #if __GLIBC__ |
| // Note: glibc has a nonstandard strerror_r that returns char* rather than POSIX's int. |
| // char *strerror_r(int errnum, char *buf, size_t n); |
| return strerror_r(errnum, buf, buflen); |
| #else |
| int rc = strerror_r(errnum, buf, buflen); |
| if (rc != 0) { |
| // (POSIX only guarantees a value other than 0. The safest |
| // way to implement this function is to use C++ and overload on the |
| // type of strerror_r to accurately distinguish GNU from POSIX.) |
| snprintf(buf, buflen, "errno %d", errnum); |
| } |
| return buf; |
| #endif |
| } |
| |
| int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) { |
| scoped_local_ref<jclass> localClass(env, env->FindClass("java/io/FileDescriptor")); |
| static jfieldID fid = env->GetFieldID(localClass.get(), "descriptor", "I"); |
| if (fileDescriptor != NULL) { |
| return env->GetIntField(fileDescriptor, fid); |
| } else { |
| return -1; |
| } |
| } |