OSDN Git Service

merge from open-source master
[android-x86/dalvik.git] / libnativehelper / JNIHelp.c
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 /*
18  * JNI helper functions.
19  */
20 #define LOG_TAG "JNIHelp"
21 #include "JNIHelp.h"
22 #include "utils/Log.h"
23
24 #include <string.h>
25 #include <assert.h>
26
27 /*
28  * Register native JNI-callable methods.
29  *
30  * "className" looks like "java/lang/String".
31  */
32 int jniRegisterNativeMethods(JNIEnv* env, const char* className,
33     const JNINativeMethod* gMethods, int numMethods)
34 {
35     jclass clazz;
36
37     LOGV("Registering %s natives\n", className);
38     clazz = (*env)->FindClass(env, className);
39     if (clazz == NULL) {
40         LOGE("Native registration unable to find class '%s'\n", className);
41         return -1;
42     }
43     if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
44         LOGE("RegisterNatives failed for '%s'\n", className);
45         return -1;
46     }
47     return 0;
48 }
49
50 /*
51  * Get a human-readable summary of an exception object.  The buffer will
52  * be populated with the "binary" class name and, if present, the
53  * exception message.
54  */
55 static void getExceptionSummary(JNIEnv* env, jthrowable excep, char* buf,
56     size_t bufLen)
57 {
58     if (excep == NULL)
59         return;
60
61     /* get the name of the exception's class; none of these should fail */
62     jclass clazz = (*env)->GetObjectClass(env, excep); // exception's class
63     jclass jlc = (*env)->GetObjectClass(env, clazz);   // java.lang.Class
64     jmethodID getNameMethod =
65         (*env)->GetMethodID(env, jlc, "getName", "()Ljava/lang/String;");
66     jstring className = (*env)->CallObjectMethod(env, clazz, getNameMethod);
67
68     /* get printable string */
69     const char* nameStr = (*env)->GetStringUTFChars(env, className, NULL);
70     if (nameStr == NULL) {
71         snprintf(buf, bufLen, "%s", "out of memory generating summary");
72         (*env)->ExceptionClear(env);            // clear OOM
73         return;
74     }
75
76     /* if the exception has a message string, get that */
77     jmethodID getThrowableMessage =
78         (*env)->GetMethodID(env, clazz, "getMessage", "()Ljava/lang/String;");
79     jstring message = (*env)->CallObjectMethod(env, excep, getThrowableMessage);
80
81     if (message != NULL) {
82         const char* messageStr = (*env)->GetStringUTFChars(env, message, NULL);
83         snprintf(buf, bufLen, "%s: %s", nameStr, messageStr);
84         if (messageStr != NULL)
85             (*env)->ReleaseStringUTFChars(env, message, messageStr);
86         else
87             (*env)->ExceptionClear(env);        // clear OOM
88     } else {
89         strncpy(buf, nameStr, bufLen);
90         buf[bufLen-1] = '\0';
91     }
92
93     (*env)->ReleaseStringUTFChars(env, className, nameStr);
94 }
95
96 /*
97  * Throw an exception with the specified class and an optional message.
98  *
99  * If an exception is currently pending, we log a warning message and
100  * clear it.
101  *
102  * Returns 0 if the specified exception was successfully thrown.  (Some
103  * sort of exception will always be pending when this returns.)
104  */
105 int jniThrowException(JNIEnv* env, const char* className, const char* msg)
106 {
107     jclass exceptionClass;
108
109     if ((*env)->ExceptionCheck(env)) {
110         /* TODO: consider creating the new exception with this as "cause" */
111         char buf[256];
112
113         jthrowable excep = (*env)->ExceptionOccurred(env);
114         (*env)->ExceptionClear(env);
115         getExceptionSummary(env, excep, buf, sizeof(buf));
116         LOGW("Discarding pending exception (%s) to throw %s\n",
117             buf, className);
118     }
119
120     exceptionClass = (*env)->FindClass(env, className);
121     if (exceptionClass == NULL) {
122         LOGE("Unable to find exception class %s\n", className);
123         /* ClassNotFoundException now pending */
124         return -1;
125     }
126
127     if ((*env)->ThrowNew(env, exceptionClass, msg) != JNI_OK) {
128         LOGE("Failed throwing '%s' '%s'\n", className, msg);
129         /* an exception, most likely OOM, will now be pending */
130         return -1;
131     }
132     return 0;
133 }
134
135 /*
136  * Throw a java.lang.NullPointerException, with an optional message.
137  */
138 int jniThrowNullPointerException(JNIEnv* env, const char* msg)
139 {
140     return jniThrowException(env, "java/lang/NullPointerException", msg);
141 }
142
143 /*
144  * Throw a java.lang.RuntimeException, with an optional message.
145  */
146 int jniThrowRuntimeException(JNIEnv* env, const char* msg)
147 {
148     return jniThrowException(env, "java/lang/RuntimeException", msg);
149 }
150
151 /*
152  * Throw a java.io.IOException, generating the message from errno.
153  */
154 int jniThrowIOException(JNIEnv* env, int errnum)
155 {
156     char buffer[80];
157     const char* message = jniStrError(errnum, buffer, sizeof(buffer));
158     return jniThrowException(env, "java/io/IOException", message);
159 }
160
161 const char* jniStrError(int errnum, char* buf, size_t buflen)
162 {
163     // note: glibc has a nonstandard strerror_r that returns char* rather
164     // than POSIX's int.
165     // char *strerror_r(int errnum, char *buf, size_t n);
166     char* ret = (char*) strerror_r(errnum, buf, buflen);
167     if (((int)ret) == 0) {
168         //POSIX strerror_r, success
169         return buf;
170     } else if (((int)ret) == -1) {
171         //POSIX strerror_r, failure
172         // (Strictly, POSIX only guarantees a value other than 0. The safest
173         // way to implement this function is to use C++ and overload on the
174         // type of strerror_r to accurately distinguish GNU from POSIX. But
175         // realistic implementations will always return -1.)
176         snprintf(buf, buflen, "errno %d", errnum);
177         return buf;
178     } else {
179         //glibc strerror_r returning a string
180         return ret;
181     }
182 }