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