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 */ 32template<typename T> 33class scoped_local_ref { 34public: 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 55private: 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 64static jclass findClass(C_JNIEnv* env, const char* className) { 65 JNIEnv* e = reinterpret_cast<JNIEnv*>(env); 66 return (*env)->FindClass(e, className); 67} 68 69extern "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 92extern "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 112int 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 118int jniThrowNullPointerException(C_JNIEnv* env, const char* msg) { 119 return jniThrowException(env, "java/lang/NullPointerException", msg); 120} 121 122int jniThrowRuntimeException(C_JNIEnv* env, const char* msg) { 123 return jniThrowException(env, "java/lang/RuntimeException", msg); 124} 125 126int 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 132const 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 149int 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