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 */
31 template<typename T>
32 class scoped_local_ref {
33 public:
scoped_local_ref(JNIEnv * env,T localRef=NULL)34 scoped_local_ref(JNIEnv* env, T localRef = NULL)
35 : mEnv(env), mLocalRef(localRef)
36 {
37 }
38
~scoped_local_ref()39 ~scoped_local_ref() {
40 reset();
41 }
42
reset(T localRef=NULL)43 void reset(T localRef = NULL) {
44 if (mLocalRef != NULL) {
45 mEnv->DeleteLocalRef(mLocalRef);
46 mLocalRef = localRef;
47 }
48 }
49
get() const50 T get() const {
51 return mLocalRef;
52 }
53
54 private:
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
findClass(JNIEnv * env,const char * className)63 static jclass findClass(JNIEnv* env, const char* className) {
64 return env->FindClass(className);
65 }
66
jniRegisterNativeMethods(JNIEnv * env,const char * className,const JNINativeMethod * gMethods,int numMethods)67 extern "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
90 extern "C"
91 #endif
jniThrowException(JNIEnv * env,const char * className,const char * msg)92 int 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
jniThrowExceptionFmt(JNIEnv * env,const char * className,const char * fmt,va_list args)111 int 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
jniThrowNullPointerException(JNIEnv * env,const char * msg)117 int jniThrowNullPointerException(JNIEnv* env, const char* msg) {
118 return jniThrowException(env, "java/lang/NullPointerException", msg);
119 }
120
jniThrowRuntimeException(JNIEnv * env,const char * msg)121 int jniThrowRuntimeException(JNIEnv* env, const char* msg) {
122 return jniThrowException(env, "java/lang/RuntimeException", msg);
123 }
124
jniThrowIOException(JNIEnv * env,int errnum)125 int 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
jniStrError(int errnum,char * buf,size_t buflen)131 const 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
jniGetFDFromFileDescriptor(JNIEnv * env,jobject fileDescriptor)148 int 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