| OLD | NEW |
| 1 /* | 1 /* |
| 2 * This file is part of Adblock Plus <http://adblockplus.org/>, | 2 * This file is part of Adblock Plus <http://adblockplus.org/>, |
| 3 * Copyright (C) 2006-2013 Eyeo GmbH | 3 * Copyright (C) 2006-2013 Eyeo GmbH |
| 4 * | 4 * |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
| 6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
| 7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
| 8 * | 8 * |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
| 13 * | 13 * |
| 14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
| 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| 16 */ | 16 */ |
| 17 | 17 |
| 18 #include <AdblockPlus.h> | 18 #include <AdblockPlus.h> |
| 19 #include "AndroidWebRequest.h" | 19 #include "AndroidWebRequest.h" |
| 20 #include "Utils.h" | 20 #include "Utils.h" |
| 21 #include "debug.h" | 21 #include "debug.h" |
| 22 | 22 |
| 23 struct JavaException : public std::exception | 23 namespace |
| 24 { | 24 { |
| 25 jthrowable ex; | 25 std::string ExtractExceptionMessage(JNIEnv* env, jthrowable throwable) |
| 26 | |
| 27 JavaException(jthrowable e) : ex(e) | |
| 28 { | 26 { |
| 27 jclass throwableClass = env->FindClass("java/lang/Throwable"); |
| 28 jmethodID throwableToStringMethodId = env->GetMethodID(throwableClass, "toSt
ring", "()Ljava/lang/String;"); |
| 29 jstring javaMessage = static_cast<jstring>(env->CallObjectMethod(throwable,
throwableToStringMethodId)); |
| 30 return "Java exception: " + GetString(env, javaMessage); |
| 29 } | 31 } |
| 30 | 32 |
| 31 const char* what() const throw() | 33 class JavaException : public std::exception |
| 32 { | 34 { |
| 33 return "Java Exception"; | 35 public: |
| 36 JavaException(JNIEnv* env) |
| 37 : env(env), throwable(env->ExceptionOccurred()) |
| 38 { |
| 39 env->ExceptionClear(); |
| 40 message = ExtractExceptionMessage(env, throwable); |
| 41 } |
| 42 |
| 43 virtual ~JavaException() throw() |
| 44 { |
| 45 } |
| 46 |
| 47 const char* what() const throw() |
| 48 { |
| 49 return message.c_str(); |
| 50 } |
| 51 |
| 52 bool IsInstanceOf(const std::string& className) const |
| 53 { |
| 54 jclass clazz = env->FindClass(className.c_str()); |
| 55 if (!clazz) |
| 56 return false; |
| 57 bool isInstance = env->IsInstanceOf(throwable, clazz); |
| 58 env->DeleteLocalRef(clazz); |
| 59 return isInstance; |
| 60 } |
| 61 |
| 62 private: |
| 63 JNIEnv* env; |
| 64 jthrowable throwable; |
| 65 std::string message; |
| 66 }; |
| 67 |
| 68 int64_t ExceptionToStatus(const JavaException& exception) |
| 69 { |
| 70 if (exception.IsInstanceOf("java/net/MalformedURLException")) |
| 71 return AdblockPlus::WebRequest::NS_ERROR_MALFORMED_URI; |
| 72 if (exception.IsInstanceOf("java/net/SocketTimeoutException")) |
| 73 return AdblockPlus::WebRequest::NS_ERROR_NET_TIMEOUT; |
| 74 return AdblockPlus::WebRequest::NS_ERROR_FAILURE; |
| 34 } | 75 } |
| 35 }; | 76 } |
| 36 | 77 |
| 37 AndroidWebRequest::AndroidWebRequest(JavaVM*& gJvm) : globalJvm(gJvm) | 78 AndroidWebRequest::AndroidWebRequest(JavaVM*& gJvm) : globalJvm(gJvm) |
| 38 { | 79 { |
| 39 JNIEnv* jniEnv = NULL; | 80 JNIEnv* jniEnv = NULL; |
| 40 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); | 81 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); |
| 41 if (stat == JNI_EDETACHED) | 82 if (stat == JNI_EDETACHED) |
| 42 { | 83 { |
| 43 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) | 84 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) |
| 44 throw std::runtime_error("Failed to get JNI environment"); | 85 throw std::runtime_error("Failed to get JNI environment"); |
| 45 } | 86 } |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 { | 138 { |
| 98 JNIEnv* jniEnv = NULL; | 139 JNIEnv* jniEnv = NULL; |
| 99 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); | 140 int stat = globalJvm->GetEnv((void **)&jniEnv, JNI_VERSION_1_6); |
| 100 if (stat == JNI_EDETACHED) | 141 if (stat == JNI_EDETACHED) |
| 101 { | 142 { |
| 102 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) | 143 if (globalJvm->AttachCurrentThread(&jniEnv, NULL) != 0) |
| 103 throw std::runtime_error("Failed to get JNI environment"); | 144 throw std::runtime_error("Failed to get JNI environment"); |
| 104 } | 145 } |
| 105 | 146 |
| 106 AdblockPlus::ServerResponse result; | 147 AdblockPlus::ServerResponse result; |
| 107 result.status = NS_ERROR_FAILURE; | |
| 108 result.responseStatus = 0; | |
| 109 | |
| 110 try | 148 try |
| 111 { | 149 { |
| 112 // URL jUrl = new URL(url) | 150 // URL jUrl = new URL(url) |
| 113 jstring jUrlStr = jniEnv->NewStringUTF(url.c_str()); | 151 jstring jUrlStr = jniEnv->NewStringUTF(url.c_str()); |
| 114 | 152 |
| 115 jobject jUrl = jniEnv->NewObject(jUrlClass, jUrlConstructorID, jUrlStr); | 153 jobject jUrl = jniEnv->NewObject(jUrlClass, jUrlConstructorID, jUrlStr); |
| 116 if (jniEnv->ExceptionCheck()) | 154 if (jniEnv->ExceptionCheck()) |
| 117 throw JavaException(jniEnv->ExceptionOccurred()); | 155 throw JavaException(jniEnv); |
| 118 jniEnv->DeleteLocalRef(jUrlStr); | 156 jniEnv->DeleteLocalRef(jUrlStr); |
| 119 | 157 |
| 120 // HttpURLConnection connection = (HttpURLConnection) jUrl.openConnection(); | 158 // HttpURLConnection connection = (HttpURLConnection) jUrl.openConnection(); |
| 121 jobject jConnection = jniEnv->CallObjectMethod(jUrl, jUrlOpenConnectionID); | 159 jobject jConnection = jniEnv->CallObjectMethod(jUrl, jUrlOpenConnectionID); |
| 122 if (jniEnv->ExceptionCheck()) | 160 if (jniEnv->ExceptionCheck()) |
| 123 throw JavaException(jniEnv->ExceptionOccurred()); | 161 throw JavaException(jniEnv); |
| 124 | 162 |
| 125 // connection.setRequestMethod("GET"); | 163 // connection.setRequestMethod("GET"); |
| 126 jstring jMethod = jniEnv->NewStringUTF("GET"); | 164 jstring jMethod = jniEnv->NewStringUTF("GET"); |
| 127 jniEnv->CallVoidMethod(jConnection, jConnectionSetMethodID, jMethod); | 165 jniEnv->CallVoidMethod(jConnection, jConnectionSetMethodID, jMethod); |
| 128 if (jniEnv->ExceptionCheck()) | 166 if (jniEnv->ExceptionCheck()) |
| 129 throw JavaException(jniEnv->ExceptionOccurred()); | 167 throw JavaException(jniEnv); |
| 130 jniEnv->DeleteLocalRef(jMethod); | 168 jniEnv->DeleteLocalRef(jMethod); |
| 131 | 169 |
| 132 for (int i = 0; i < requestHeaders.size(); i++) | 170 for (int i = 0; i < requestHeaders.size(); i++) |
| 133 { | 171 { |
| 134 // connection.setRequestProperty(requestHeaders[i].first, requestHeaders[i
].second); | 172 // connection.setRequestProperty(requestHeaders[i].first, requestHeaders[i
].second); |
| 135 jstring jHeader = jniEnv->NewStringUTF(requestHeaders[i].first.c_str()); | 173 jstring jHeader = jniEnv->NewStringUTF(requestHeaders[i].first.c_str()); |
| 136 jstring jValue = jniEnv->NewStringUTF(requestHeaders[i].second.c_str()); | 174 jstring jValue = jniEnv->NewStringUTF(requestHeaders[i].second.c_str()); |
| 137 jniEnv->CallVoidMethod(jConnection, jConnectionSetRequestPropertyID, jHead
er, jValue); | 175 jniEnv->CallVoidMethod(jConnection, jConnectionSetRequestPropertyID, jHead
er, jValue); |
| 138 if (jniEnv->ExceptionCheck()) | 176 if (jniEnv->ExceptionCheck()) |
| 139 throw JavaException(jniEnv->ExceptionOccurred()); | 177 throw JavaException(jniEnv); |
| 140 jniEnv->DeleteLocalRef(jHeader); | 178 jniEnv->DeleteLocalRef(jHeader); |
| 141 jniEnv->DeleteLocalRef(jValue); | 179 jniEnv->DeleteLocalRef(jValue); |
| 142 } | 180 } |
| 143 | 181 |
| 144 // connection.connect(); | 182 // connection.connect(); |
| 145 jniEnv->CallVoidMethod(jConnection, jConnectionConnectID); | 183 jniEnv->CallVoidMethod(jConnection, jConnectionConnectID); |
| 146 if (jniEnv->ExceptionCheck()) | 184 if (jniEnv->ExceptionCheck()) |
| 147 throw JavaException(jniEnv->ExceptionOccurred()); | 185 throw JavaException(jniEnv); |
| 148 | 186 |
| 149 // int lenghtOfFile = connection.getContentLength(); | 187 // int lenghtOfFile = connection.getContentLength(); |
| 150 jint lenghtOfFile = jniEnv->CallIntMethod(jConnection, jConnectionGetContent
LengthID); | 188 jint lenghtOfFile = jniEnv->CallIntMethod(jConnection, jConnectionGetContent
LengthID); |
| 151 if (jniEnv->ExceptionCheck()) | 189 if (jniEnv->ExceptionCheck()) |
| 152 throw JavaException(jniEnv->ExceptionOccurred()); | 190 throw JavaException(jniEnv); |
| 153 | 191 |
| 154 D(D_WARN, "Size: %d", lenghtOfFile); | 192 D(D_WARN, "Size: %d", lenghtOfFile); |
| 155 | 193 |
| 156 // result.responseStatus = connection.getResponseCode(); | 194 // result.responseStatus = connection.getResponseCode(); |
| 157 result.responseStatus = jniEnv->CallIntMethod(jConnection, jConnectionGetRes
ponseCodeID); | 195 result.responseStatus = jniEnv->CallIntMethod(jConnection, jConnectionGetRes
ponseCodeID); |
| 158 if (jniEnv->ExceptionCheck()) | 196 if (jniEnv->ExceptionCheck()) |
| 159 throw JavaException(jniEnv->ExceptionOccurred()); | 197 throw JavaException(jniEnv); |
| 160 | 198 |
| 161 /* Read response data */ | 199 /* Read response data */ |
| 162 | 200 |
| 163 // String jEncoding = connection.getContentEncoding(); | 201 // String jEncoding = connection.getContentEncoding(); |
| 164 jstring jEncoding = (jstring) jniEnv->CallObjectMethod(jConnection, jConnect
ionGetContentEncodingID); | 202 jstring jEncoding = (jstring) jniEnv->CallObjectMethod(jConnection, jConnect
ionGetContentEncodingID); |
| 165 if (jniEnv->ExceptionCheck()) | 203 if (jniEnv->ExceptionCheck()) |
| 166 throw JavaException(jniEnv->ExceptionOccurred()); | 204 throw JavaException(jniEnv); |
| 167 | 205 |
| 168 if (jEncoding == NULL) | 206 if (jEncoding == NULL) |
| 169 jEncoding = jniEnv->NewStringUTF("utf-8"); | 207 jEncoding = jniEnv->NewStringUTF("utf-8"); |
| 170 | 208 |
| 171 // InputStream jis = connection.getInputStream(); | 209 // InputStream jis = connection.getInputStream(); |
| 172 jobject jis = jniEnv->CallObjectMethod(jConnection, jConnectionGetInputStrea
mID); | 210 jobject jis = jniEnv->CallObjectMethod(jConnection, jConnectionGetInputStrea
mID); |
| 173 if (jniEnv->ExceptionCheck()) | 211 if (jniEnv->ExceptionCheck()) |
| 174 throw JavaException(jniEnv->ExceptionOccurred()); | 212 throw JavaException(jniEnv); |
| 175 | 213 |
| 176 // InputStreamReader jisr = new InputStreamReader(jis, jEncoding); | 214 // InputStreamReader jisr = new InputStreamReader(jis, jEncoding); |
| 177 jobject jisr = jniEnv->NewObject(jInputStreamReaderClass, jInputStreamReader
ConstructorID, jis, jEncoding); | 215 jobject jisr = jniEnv->NewObject(jInputStreamReaderClass, jInputStreamReader
ConstructorID, jis, jEncoding); |
| 178 if (jniEnv->ExceptionCheck()) | 216 if (jniEnv->ExceptionCheck()) |
| 179 throw JavaException(jniEnv->ExceptionOccurred()); | 217 throw JavaException(jniEnv); |
| 180 | 218 |
| 181 jniEnv->DeleteLocalRef(jEncoding); | 219 jniEnv->DeleteLocalRef(jEncoding); |
| 182 | 220 |
| 183 // BufferedReader jin = new BufferedReader(jisr); | 221 // BufferedReader jin = new BufferedReader(jisr); |
| 184 jobject jin = jniEnv->NewObject(jBufferedReaderClass, jBufferedReaderConstru
ctorID, jisr); | 222 jobject jin = jniEnv->NewObject(jBufferedReaderClass, jBufferedReaderConstru
ctorID, jisr); |
| 185 if (jniEnv->ExceptionCheck()) | 223 if (jniEnv->ExceptionCheck()) |
| 186 throw JavaException(jniEnv->ExceptionOccurred()); | 224 throw JavaException(jniEnv); |
| 187 | 225 |
| 188 // char[] jBuffer = new char[0x10000]; | 226 // char[] jBuffer = new char[0x10000]; |
| 189 jcharArray jBuffer = jniEnv->NewCharArray(0x10000); | 227 jcharArray jBuffer = jniEnv->NewCharArray(0x10000); |
| 190 | 228 |
| 191 // StringBuilder jout = new StringBuilder(); | 229 // StringBuilder jout = new StringBuilder(); |
| 192 jobject jout = jniEnv->NewObject(jStringBuilderClass, jStringBuilderConstruc
torID); | 230 jobject jout = jniEnv->NewObject(jStringBuilderClass, jStringBuilderConstruc
torID); |
| 193 if (jniEnv->ExceptionCheck()) | 231 if (jniEnv->ExceptionCheck()) |
| 194 throw JavaException(jniEnv->ExceptionOccurred()); | 232 throw JavaException(jniEnv); |
| 195 | 233 |
| 196 jlong total = 0; | 234 jlong total = 0; |
| 197 jint read; | 235 jint read; |
| 198 | 236 |
| 199 jint jBufferLength = (jint) jniEnv->GetArrayLength(jBuffer); | 237 jint jBufferLength = (jint) jniEnv->GetArrayLength(jBuffer); |
| 200 | 238 |
| 201 do | 239 do |
| 202 { | 240 { |
| 203 // read = jin.read(buffer, 0, buffer.length); | 241 // read = jin.read(buffer, 0, buffer.length); |
| 204 read = jniEnv->CallIntMethod(jin, jBufferedReaderReadID, jBuffer, 0, jBuff
erLength); | 242 read = jniEnv->CallIntMethod(jin, jBufferedReaderReadID, jBuffer, 0, jBuff
erLength); |
| 205 if (jniEnv->ExceptionCheck()) | 243 if (jniEnv->ExceptionCheck()) |
| 206 throw JavaException(jniEnv->ExceptionOccurred()); | 244 throw JavaException(jniEnv); |
| 207 | 245 |
| 208 if (read > 0) | 246 if (read > 0) |
| 209 { | 247 { |
| 210 // jout.append(buffer, 0, read); | 248 // jout.append(buffer, 0, read); |
| 211 jniEnv->CallObjectMethod(jout, jStringBuilderAppendID, jBuffer, 0, jBuff
erLength); | 249 jniEnv->CallObjectMethod(jout, jStringBuilderAppendID, jBuffer, 0, jBuff
erLength); |
| 212 if (jniEnv->ExceptionCheck()) | 250 if (jniEnv->ExceptionCheck()) |
| 213 throw JavaException(jniEnv->ExceptionOccurred()); | 251 throw JavaException(jniEnv); |
| 214 | 252 |
| 215 total += read; | 253 total += read; |
| 216 } | 254 } |
| 217 } | 255 } |
| 218 while (read >= 0); | 256 while (read >= 0); |
| 219 | 257 |
| 220 // String jData = out.toString(); | 258 // String jData = out.toString(); |
| 221 jstring jData = (jstring) jniEnv->CallObjectMethod(jout, jStringBuilderToStr
ingID); | 259 jstring jData = (jstring) jniEnv->CallObjectMethod(jout, jStringBuilderToStr
ingID); |
| 222 if (jniEnv->ExceptionCheck()) | 260 if (jniEnv->ExceptionCheck()) |
| 223 throw JavaException(jniEnv->ExceptionOccurred()); | 261 throw JavaException(jniEnv); |
| 224 | 262 |
| 225 result.responseText = GetString(jniEnv, jData); | 263 result.responseText = GetString(jniEnv, jData); |
| 226 | 264 |
| 227 // jin.close(); | 265 // jin.close(); |
| 228 jniEnv->CallVoidMethod(jin, jBufferedReaderCloseID); | 266 jniEnv->CallVoidMethod(jin, jBufferedReaderCloseID); |
| 229 if (jniEnv->ExceptionCheck()) | 267 if (jniEnv->ExceptionCheck()) |
| 230 throw JavaException(jniEnv->ExceptionOccurred()); | 268 throw JavaException(jniEnv); |
| 231 | 269 |
| 232 jint i = 0; | 270 jint i = 0; |
| 233 while (true) | 271 while (true) |
| 234 { | 272 { |
| 235 // String jHeaderName = connection.getHeaderFieldKey(i) | 273 // String jHeaderName = connection.getHeaderFieldKey(i) |
| 236 jstring jHeaderName = (jstring) jniEnv->CallObjectMethod(jConnection, jCon
nectionGetHeaderFieldKeyID, i); | 274 jstring jHeaderName = (jstring) jniEnv->CallObjectMethod(jConnection, jCon
nectionGetHeaderFieldKeyID, i); |
| 237 if (jniEnv->ExceptionCheck()) | 275 if (jniEnv->ExceptionCheck()) |
| 238 throw JavaException(jniEnv->ExceptionOccurred()); | 276 throw JavaException(jniEnv); |
| 239 | 277 |
| 240 // String jHeaderValue = connection.getHeaderField(i) | 278 // String jHeaderValue = connection.getHeaderField(i) |
| 241 jstring jHeaderValue = (jstring) jniEnv->CallObjectMethod(jConnection, jCo
nnectionGetHeaderFieldID, i); | 279 jstring jHeaderValue = (jstring) jniEnv->CallObjectMethod(jConnection, jCo
nnectionGetHeaderFieldID, i); |
| 242 if (jniEnv->ExceptionCheck()) | 280 if (jniEnv->ExceptionCheck()) |
| 243 throw JavaException(jniEnv->ExceptionOccurred()); | 281 throw JavaException(jniEnv); |
| 244 | 282 |
| 245 if (!jHeaderValue) | 283 if (!jHeaderValue) |
| 246 break; | 284 break; |
| 247 | 285 |
| 248 std::string headerName = GetString(jniEnv, jHeaderName); | 286 std::string headerName = GetString(jniEnv, jHeaderName); |
| 249 std::string headerValue = GetString(jniEnv, jHeaderValue); | 287 std::string headerValue = GetString(jniEnv, jHeaderValue); |
| 250 | 288 |
| 251 headerName = TrimString(headerName); | 289 headerName = TrimString(headerName); |
| 252 headerValue = TrimString(headerValue); | 290 headerValue = TrimString(headerValue); |
| 253 | 291 |
| 254 std::transform(headerName.begin(), headerName.end(), headerName.begin(), :
:tolower); | 292 std::transform(headerName.begin(), headerName.end(), headerName.begin(), :
:tolower); |
| 255 | 293 |
| 256 result.responseHeaders.push_back(std::pair<std::string, std::string>(heade
rName, headerValue)); | 294 result.responseHeaders.push_back(std::pair<std::string, std::string>(heade
rName, headerValue)); |
| 257 | 295 |
| 258 i++; | 296 i++; |
| 259 } | 297 } |
| 260 D(D_WARN, "Finished downloading"); | 298 D(D_WARN, "Finished downloading"); |
| 261 | 299 |
| 262 result.status = AdblockPlus::DefaultWebRequest::NS_OK; | 300 result.status = NS_OK; |
| 263 } | 301 } |
| 264 catch(JavaException& e) | 302 catch(JavaException& e) |
| 265 { | 303 { |
| 266 jniEnv->ExceptionClear(); | 304 result.responseStatus = 0; |
| 267 jclass jThrowableClass = jniEnv->FindClass("java/lang/Throwable"); | 305 result.status = ExceptionToStatus(e); |
| 268 jmethodID jThrowableToStringID = jniEnv->GetMethodID(jThrowableClass, "toStr
ing", "()Ljava/lang/String;"); | 306 D(D_ERROR, "%s", e.what()); |
| 269 jstring jMsg = (jstring) jniEnv->CallObjectMethod(e.ex, jThrowableToStringID
); | |
| 270 const char* msg = jniEnv->GetStringUTFChars(jMsg, 0); | |
| 271 D(D_ERROR, "Java Exception: %s", msg); | |
| 272 jniEnv->ReleaseStringUTFChars(jMsg, msg); | |
| 273 jniEnv->DeleteLocalRef(jMsg); | |
| 274 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; | |
| 275 } | 307 } |
| 276 catch (const std::exception& e) | 308 catch (const std::exception& e) |
| 277 { | 309 { |
| 278 D(D_ERROR, "Exception: %s", e.what()); | 310 D(D_ERROR, "Exception: %s", e.what()); |
| 279 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; | 311 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; |
| 280 } | 312 } |
| 281 catch (...) | 313 catch (...) |
| 282 { | 314 { |
| 283 D(D_ERROR, "Unknown exception"); | 315 D(D_ERROR, "Unknown exception"); |
| 284 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; | 316 result.status = AdblockPlus::DefaultWebRequest::NS_ERROR_FAILURE; |
| 285 } | 317 } |
| 286 | 318 |
| 287 if (stat == JNI_EDETACHED) | 319 if (stat == JNI_EDETACHED) |
| 288 globalJvm->DetachCurrentThread(); | 320 globalJvm->DetachCurrentThread(); |
| 289 | 321 |
| 290 return result; | 322 return result; |
| 291 } | 323 } |
| OLD | NEW |