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:
scoped_local_ref(C_JNIEnv * env,T localRef=NULL)35 scoped_local_ref(C_JNIEnv* env, T localRef = NULL)
36 : mEnv(env), mLocalRef(localRef)
37 {
38 }
39
~scoped_local_ref()40 ~scoped_local_ref() {
41 reset();
42 }
43
reset(T localRef=NULL)44 void reset(T localRef = NULL) {
45 if (mLocalRef != NULL) {
46 (*mEnv)->DeleteLocalRef(reinterpret_cast<JNIEnv*>(mEnv), mLocalRef);
47 mLocalRef = localRef;
48 }
49 }
50
get() const51 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
findClass(C_JNIEnv * env,const char * className)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
jniRegisterNativeMethods(C_JNIEnv * env,const char * className,const JNINativeMethod * gMethods,int numMethods)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
jniThrowException(C_JNIEnv * c_env,const char * className,const char * msg)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
jniThrowExceptionFmt(C_JNIEnv * env,const char * className,const char * fmt,va_list args)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
jniThrowNullPointerException(C_JNIEnv * env,const char * msg)118 int jniThrowNullPointerException(C_JNIEnv* env, const char* msg) {
119 return jniThrowException(env, "java/lang/NullPointerException", msg);
120 }
121
jniThrowRuntimeException(C_JNIEnv * env,const char * msg)122 int jniThrowRuntimeException(C_JNIEnv* env, const char* msg) {
123 return jniThrowException(env, "java/lang/RuntimeException", msg);
124 }
125
jniThrowIOException(C_JNIEnv * env,int errnum)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
jniStrError(int errnum,char * buf,size_t buflen)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
jniGetFDFromFileDescriptor(C_JNIEnv * env,jobject fileDescriptor)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