1 /* 2 * Copyright (C) 2006 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 #define LOG_TAG "JNIHelp" 18 19 #include "JNIHelp.h" 20 21 #include <android/log.h> 22 #include "log_compat.h" 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <assert.h> 28 29 /** 30 * Equivalent to ScopedLocalRef, but for C_JNIEnv instead. (And slightly more powerful.) 31 */ 32 template<typename T> 33 class scoped_local_ref { 34 public: 35 scoped_local_ref(C_JNIEnv* env, T localRef = NULL) 36 : mEnv(env), mLocalRef(localRef) 37 { 38 } 39 40 ~scoped_local_ref() { 41 reset(); 42 } 43 44 void reset(T localRef = NULL) { 45 if (mLocalRef != NULL) { 46 (*mEnv)->DeleteLocalRef(reinterpret_cast<JNIEnv*>(mEnv), mLocalRef); 47 mLocalRef = localRef; 48 } 49 } 50 51 T get() const { 52 return mLocalRef; 53 } 54 55 private: 56 C_JNIEnv* mEnv; 57 T mLocalRef; 58 59 // Disallow copy and assignment. 60 scoped_local_ref(const scoped_local_ref&); 61 void operator=(const scoped_local_ref&); 62 }; 63 64 static jclass findClass(C_JNIEnv* env, const char* className) { 65 JNIEnv* e = reinterpret_cast<JNIEnv*>(env); 66 return (*env)->FindClass(e, className); 67 } 68 69 extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className, 70 const JNINativeMethod* gMethods, int numMethods) 71 { 72 JNIEnv* e = reinterpret_cast<JNIEnv*>(env); 73 74 ALOGV("Registering %s's %d native methods...", className, numMethods); 75 76 scoped_local_ref<jclass> c(env, findClass(env, className)); 77 if (c.get() == NULL) { 78 char* msg; 79 asprintf(&msg, "Native registration unable to find class '%s'; aborting...", className); 80 e->FatalError(msg); 81 } 82 83 if ((*env)->RegisterNatives(e, c.get(), gMethods, numMethods) < 0) { 84 char* msg; 85 asprintf(&msg, "RegisterNatives failed for '%s'; aborting...", className); 86 e->FatalError(msg); 87 } 88 89 return 0; 90 } 91 92 extern "C" int jniThrowException(C_JNIEnv* c_env, const char* className, const char* msg) { 93 JNIEnv* env = reinterpret_cast<JNIEnv*>(c_env); 94 jclass exceptionClass = env->FindClass(className); 95 96 if (exceptionClass == NULL) { 97 ALOGD("Unable to find exception class %s", className); 98 /* ClassNotFoundException now pending */ 99 return -1; 100 } 101 102 if (env->ThrowNew(exceptionClass, msg) != JNI_OK) { 103 ALOGD("Failed throwing '%s' '%s'", className, msg); 104 /* an exception, most likely OOM, will now be pending */ 105 return -1; 106 } 107 108 env->DeleteLocalRef(exceptionClass); 109 return 0; 110 } 111 112 int jniThrowExceptionFmt(C_JNIEnv* env, const char* className, const char* fmt, va_list args) { 113 char msgBuf[512]; 114 vsnprintf(msgBuf, sizeof(msgBuf), fmt, args); 115 return jniThrowException(env, className, msgBuf); 116 } 117 118 int jniThrowNullPointerException(C_JNIEnv* env, const char* msg) { 119 return jniThrowException(env, "java/lang/NullPointerException", msg); 120 } 121 122 int jniThrowRuntimeException(C_JNIEnv* env, const char* msg) { 123 return jniThrowException(env, "java/lang/RuntimeException", msg); 124 } 125 126 int jniThrowIOException(C_JNIEnv* env, int errnum) { 127 char buffer[80]; 128 const char* message = jniStrError(errnum, buffer, sizeof(buffer)); 129 return jniThrowException(env, "java/io/IOException", message); 130 } 131 132 const char* jniStrError(int errnum, char* buf, size_t buflen) { 133 #if __GLIBC__ 134 // Note: glibc has a nonstandard strerror_r that returns char* rather than POSIX's int. 135 // char *strerror_r(int errnum, char *buf, size_t n); 136 return strerror_r(errnum, buf, buflen); 137 #else 138 int rc = strerror_r(errnum, buf, buflen); 139 if (rc != 0) { 140 // (POSIX only guarantees a value other than 0. The safest 141 // way to implement this function is to use C++ and overload on the 142 // type of strerror_r to accurately distinguish GNU from POSIX.) 143 snprintf(buf, buflen, "errno %d", errnum); 144 } 145 return buf; 146 #endif 147 } 148 149 int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor) { 150 JNIEnv* e = reinterpret_cast<JNIEnv*>(env); 151 scoped_local_ref<jclass> localClass(env, e->FindClass("java/io/FileDescriptor")); 152 static jfieldID fid = e->GetFieldID(localClass.get(), "descriptor", "I"); 153 if (fileDescriptor != NULL) { 154 return (*env)->GetIntField(e, fileDescriptor, fid); 155 } else { 156 return -1; 157 } 158 } 159