1 /* 2 * Copyright (C) 2008 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 * Support for -Xcheck:jni (the "careful" version of the JNI interfaces). 19 * 20 * We want to verify types, make sure class and field IDs are valid, and 21 * ensure that JNI's semantic expectations are being met. JNI seems to 22 * be relatively lax when it comes to requirements for permission checks, 23 * e.g. access to private methods is generally allowed from anywhere. 24 */ 25 26 #include "Dalvik.h" 27 #include "JniInternal.h" 28 29 #include <sys/mman.h> 30 #include <zlib.h> 31 32 /* 33 * Abort if we are configured to bail out on JNI warnings. 34 */ 35 static void abortMaybe() { 36 if (!gDvmJni.warnOnly) { 37 dvmDumpThread(dvmThreadSelf(), false); 38 dvmAbort(); 39 } 40 } 41 42 /* 43 * =========================================================================== 44 * JNI call bridge wrapper 45 * =========================================================================== 46 */ 47 48 /* 49 * Check the result of a native method call that returns an object reference. 50 * 51 * The primary goal here is to verify that native code is returning the 52 * correct type of object. If it's declared to return a String but actually 53 * returns a byte array, things will fail in strange ways later on. 54 * 55 * This can be a fairly expensive operation, since we have to look up the 56 * return type class by name in method->clazz' class loader. We take a 57 * shortcut here and allow the call to succeed if the descriptor strings 58 * match. This will allow some false-positives when a class is redefined 59 * by a class loader, but that's rare enough that it doesn't seem worth 60 * testing for. 61 * 62 * At this point, pResult->l has already been converted to an object pointer. 63 */ 64 static void checkCallResultCommon(const u4* args, const JValue* pResult, 65 const Method* method, Thread* self) 66 { 67 assert(pResult->l != NULL); 68 const Object* resultObj = (const Object*) pResult->l; 69 70 if (resultObj == kInvalidIndirectRefObject) { 71 ALOGW("JNI WARNING: invalid reference returned from native code"); 72 const Method* method = dvmGetCurrentJNIMethod(); 73 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 74 ALOGW(" in %s.%s:%s", method->clazz->descriptor, method->name, desc); 75 free(desc); 76 abortMaybe(); 77 return; 78 } 79 80 ClassObject* objClazz = resultObj->clazz; 81 82 /* 83 * Make sure that pResult->l is an instance of the type this 84 * method was expected to return. 85 */ 86 const char* declType = dexProtoGetReturnType(&method->prototype); 87 const char* objType = objClazz->descriptor; 88 if (strcmp(declType, objType) == 0) { 89 /* names match; ignore class loader issues and allow it */ 90 ALOGV("Check %s.%s: %s io %s (FAST-OK)", 91 method->clazz->descriptor, method->name, objType, declType); 92 } else { 93 /* 94 * Names didn't match. We need to resolve declType in the context 95 * of method->clazz->classLoader, and compare the class objects 96 * for equality. 97 * 98 * Since we're returning an instance of declType, it's safe to 99 * assume that it has been loaded and initialized (or, for the case 100 * of an array, generated). However, the current class loader may 101 * not be listed as an initiating loader, so we can't just look for 102 * it in the loaded-classes list. 103 */ 104 ClassObject* declClazz = dvmFindClassNoInit(declType, method->clazz->classLoader); 105 if (declClazz == NULL) { 106 ALOGW("JNI WARNING: method declared to return '%s' returned '%s'", 107 declType, objType); 108 ALOGW(" failed in %s.%s ('%s' not found)", 109 method->clazz->descriptor, method->name, declType); 110 abortMaybe(); 111 return; 112 } 113 if (!dvmInstanceof(objClazz, declClazz)) { 114 ALOGW("JNI WARNING: method declared to return '%s' returned '%s'", 115 declType, objType); 116 ALOGW(" failed in %s.%s", 117 method->clazz->descriptor, method->name); 118 abortMaybe(); 119 return; 120 } else { 121 ALOGV("Check %s.%s: %s io %s (SLOW-OK)", 122 method->clazz->descriptor, method->name, objType, declType); 123 } 124 } 125 } 126 127 /* 128 * Determine if we need to check the return type coming out of the call. 129 * 130 * (We don't simply do this at the top of checkCallResultCommon() because 131 * this is on the critical path for native method calls.) 132 */ 133 static inline bool callNeedsCheck(const u4* args, JValue* pResult, 134 const Method* method, Thread* self) 135 { 136 return (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL); 137 } 138 139 /* 140 * Check a call into native code. 141 */ 142 void dvmCheckCallJNIMethod(const u4* args, JValue* pResult, 143 const Method* method, Thread* self) 144 { 145 dvmCallJNIMethod(args, pResult, method, self); 146 if (callNeedsCheck(args, pResult, method, self)) { 147 checkCallResultCommon(args, pResult, method, self); 148 } 149 } 150 151 /* 152 * =========================================================================== 153 * JNI function helpers 154 * =========================================================================== 155 */ 156 157 static inline const JNINativeInterface* baseEnv(JNIEnv* env) { 158 return ((JNIEnvExt*) env)->baseFuncTable; 159 } 160 161 static inline const JNIInvokeInterface* baseVm(JavaVM* vm) { 162 return ((JavaVMExt*) vm)->baseFuncTable; 163 } 164 165 class ScopedCheckJniThreadState { 166 public: 167 explicit ScopedCheckJniThreadState(JNIEnv* env) { 168 dvmChangeStatus(NULL, THREAD_RUNNING); 169 } 170 171 ~ScopedCheckJniThreadState() { 172 dvmChangeStatus(NULL, THREAD_NATIVE); 173 } 174 175 private: 176 // Disallow copy and assignment. 177 ScopedCheckJniThreadState(const ScopedCheckJniThreadState&); 178 void operator=(const ScopedCheckJniThreadState&); 179 }; 180 181 /* 182 * Flags passed into ScopedCheck. 183 */ 184 #define kFlag_Default 0x0000 185 186 #define kFlag_CritBad 0x0000 /* calling while in critical is bad */ 187 #define kFlag_CritOkay 0x0001 /* ...okay */ 188 #define kFlag_CritGet 0x0002 /* this is a critical "get" */ 189 #define kFlag_CritRelease 0x0003 /* this is a critical "release" */ 190 #define kFlag_CritMask 0x0003 /* bit mask to get "crit" value */ 191 192 #define kFlag_ExcepBad 0x0000 /* raised exceptions are bad */ 193 #define kFlag_ExcepOkay 0x0004 /* ...okay */ 194 195 #define kFlag_Release 0x0010 /* are we in a non-critical release function? */ 196 #define kFlag_NullableUtf 0x0020 /* are our UTF parameters nullable? */ 197 198 #define kFlag_Invocation 0x8000 /* Part of the invocation interface (JavaVM*) */ 199 200 static const char* indirectRefKindName(IndirectRef iref) 201 { 202 return indirectRefKindToString(indirectRefKind(iref)); 203 } 204 205 class ScopedCheck { 206 public: 207 // For JNIEnv* functions. 208 explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) { 209 init(env, flags, functionName, true); 210 checkThread(flags); 211 } 212 213 // For JavaVM* functions. 214 explicit ScopedCheck(bool hasMethod, const char* functionName) { 215 init(NULL, kFlag_Invocation, functionName, hasMethod); 216 } 217 218 /* 219 * In some circumstances the VM will screen class names, but it doesn't 220 * for class lookup. When things get bounced through a class loader, they 221 * can actually get normalized a couple of times; as a result, passing in 222 * a class name like "java.lang.Thread" instead of "java/lang/Thread" will 223 * work in some circumstances. 224 * 225 * This is incorrect and could cause strange behavior or compatibility 226 * problems, so we want to screen that out here. 227 * 228 * We expect "fully-qualified" class names, like "java/lang/Thread" or 229 * "[Ljava/lang/Object;". 230 */ 231 void checkClassName(const char* className) { 232 if (!dexIsValidClassName(className, false)) { 233 ALOGW("JNI WARNING: illegal class name '%s' (%s)", className, mFunctionName); 234 ALOGW(" (should be formed like 'dalvik/system/DexFile')"); 235 ALOGW(" or '[Ldalvik/system/DexFile;' or '[[B')"); 236 abortMaybe(); 237 } 238 } 239 240 void checkFieldTypeForGet(jfieldID fid, const char* expectedSignature, bool isStatic) { 241 if (fid == NULL) { 242 ALOGW("JNI WARNING: null jfieldID (%s)", mFunctionName); 243 showLocation(); 244 abortMaybe(); 245 } 246 247 bool printWarn = false; 248 Field* field = (Field*) fid; 249 const char* actualSignature = field->signature; 250 if (*expectedSignature == 'L') { 251 // 'actualSignature' has the exact type. 252 // We just know we're expecting some kind of reference. 253 if (*actualSignature != 'L' && *actualSignature != '[') { 254 printWarn = true; 255 } 256 } else if (*actualSignature != *expectedSignature) { 257 printWarn = true; 258 } 259 260 if (!printWarn && isStatic && !dvmIsStaticField(field)) { 261 if (isStatic) { 262 ALOGW("JNI WARNING: accessing non-static field %s as static", field->name); 263 } else { 264 ALOGW("JNI WARNING: accessing static field %s as non-static", field->name); 265 } 266 printWarn = true; 267 } 268 269 if (printWarn) { 270 ALOGW("JNI WARNING: %s for field '%s' of expected type %s, got %s", 271 mFunctionName, field->name, expectedSignature, actualSignature); 272 showLocation(); 273 abortMaybe(); 274 } 275 } 276 277 /* 278 * Verify that the field is of the appropriate type. If the field has an 279 * object type, "jobj" is the object we're trying to assign into it. 280 * 281 * Works for both static and instance fields. 282 */ 283 void checkFieldTypeForSet(jobject jobj, jfieldID fieldID, PrimitiveType prim, bool isStatic) { 284 if (fieldID == NULL) { 285 ALOGW("JNI WARNING: null jfieldID (%s)", mFunctionName); 286 showLocation(); 287 abortMaybe(); 288 } 289 290 bool printWarn = false; 291 Field* field = (Field*) fieldID; 292 if ((field->signature[0] == 'L' || field->signature[0] == '[') && jobj != NULL) { 293 ScopedCheckJniThreadState ts(mEnv); 294 Object* obj = dvmDecodeIndirectRef(self(), jobj); 295 /* 296 * If jobj is a weak global ref whose referent has been cleared, 297 * obj will be NULL. Otherwise, obj should always be non-NULL 298 * and valid. 299 */ 300 if (obj != NULL && !dvmIsHeapAddress(obj)) { 301 ALOGW("JNI WARNING: field operation (%s) on invalid %s reference (%p)", 302 mFunctionName, indirectRefKindName(jobj), jobj); 303 printWarn = true; 304 } else { 305 ClassObject* fieldClass = dvmFindLoadedClass(field->signature); 306 ClassObject* objClass = obj->clazz; 307 308 assert(fieldClass != NULL); 309 assert(objClass != NULL); 310 311 if (!dvmInstanceof(objClass, fieldClass)) { 312 ALOGW("JNI WARNING: %s for field '%s' expected type %s, got %s", 313 mFunctionName, field->name, field->signature, objClass->descriptor); 314 printWarn = true; 315 } 316 } 317 } else if (dexGetPrimitiveTypeFromDescriptorChar(field->signature[0]) != prim) { 318 ALOGW("JNI WARNING: %s for field '%s' expected type %s, got %s", 319 mFunctionName, field->name, field->signature, primitiveTypeToName(prim)); 320 printWarn = true; 321 } else if (isStatic && !dvmIsStaticField(field)) { 322 if (isStatic) { 323 ALOGW("JNI WARNING: %s for non-static field '%s'", mFunctionName, field->name); 324 } else { 325 ALOGW("JNI WARNING: %s for static field '%s'", mFunctionName, field->name); 326 } 327 printWarn = true; 328 } 329 330 if (printWarn) { 331 showLocation(); 332 abortMaybe(); 333 } 334 } 335 336 /* 337 * Verify that this instance field ID is valid for this object. 338 * 339 * Assumes "jobj" has already been validated. 340 */ 341 void checkInstanceFieldID(jobject jobj, jfieldID fieldID) { 342 ScopedCheckJniThreadState ts(mEnv); 343 344 Object* obj = dvmDecodeIndirectRef(self(), jobj); 345 if (!dvmIsHeapAddress(obj)) { 346 ALOGW("JNI ERROR: %s on invalid reference (%p)", mFunctionName, jobj); 347 dvmAbort(); 348 } 349 350 /* 351 * Check this class and all of its superclasses for a matching field. 352 * Don't need to scan interfaces. 353 */ 354 ClassObject* clazz = obj->clazz; 355 while (clazz != NULL) { 356 if ((InstField*) fieldID >= clazz->ifields && 357 (InstField*) fieldID < clazz->ifields + clazz->ifieldCount) { 358 return; 359 } 360 361 clazz = clazz->super; 362 } 363 364 ALOGW("JNI WARNING: instance jfieldID %p not valid for class %s (%s)", 365 fieldID, obj->clazz->descriptor, mFunctionName); 366 showLocation(); 367 abortMaybe(); 368 } 369 370 /* 371 * Verify that the pointer value is non-NULL. 372 */ 373 void checkNonNull(const void* ptr) { 374 if (ptr == NULL) { 375 ALOGW("JNI WARNING: invalid null pointer (%s)", mFunctionName); 376 abortMaybe(); 377 } 378 } 379 380 /* 381 * Verify that the method's return type matches the type of call. 382 * 'expectedType' will be "L" for all objects, including arrays. 383 */ 384 void checkSig(jmethodID methodID, const char* expectedType, bool isStatic) { 385 const Method* method = (const Method*) methodID; 386 bool printWarn = false; 387 388 if (*expectedType != method->shorty[0]) { 389 ALOGW("JNI WARNING: %s expected return type '%s'", mFunctionName, expectedType); 390 printWarn = true; 391 } else if (isStatic && !dvmIsStaticMethod(method)) { 392 if (isStatic) { 393 ALOGW("JNI WARNING: calling non-static method with static call %s", mFunctionName); 394 } else { 395 ALOGW("JNI WARNING: calling static method with non-static call %s", mFunctionName); 396 } 397 printWarn = true; 398 } 399 400 if (printWarn) { 401 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 402 ALOGW(" calling %s.%s %s", method->clazz->descriptor, method->name, desc); 403 free(desc); 404 showLocation(); 405 abortMaybe(); 406 } 407 } 408 409 /* 410 * Verify that this static field ID is valid for this class. 411 * 412 * Assumes "jclazz" has already been validated. 413 */ 414 void checkStaticFieldID(jclass jclazz, jfieldID fieldID) { 415 ScopedCheckJniThreadState ts(mEnv); 416 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(self(), jclazz); 417 StaticField* base = &clazz->sfields[0]; 418 int fieldCount = clazz->sfieldCount; 419 if ((StaticField*) fieldID < base || (StaticField*) fieldID >= base + fieldCount) { 420 ALOGW("JNI WARNING: static fieldID %p not valid for class %s (%s)", 421 fieldID, clazz->descriptor, mFunctionName); 422 ALOGW(" base=%p count=%d", base, fieldCount); 423 showLocation(); 424 abortMaybe(); 425 } 426 } 427 428 /* 429 * Verify that "methodID" is appropriate for "clazz". 430 * 431 * A mismatch isn't dangerous, because the jmethodID defines the class. In 432 * fact, jclazz is unused in the implementation. It's best if we don't 433 * allow bad code in the system though. 434 * 435 * Instances of "jclazz" must be instances of the method's declaring class. 436 */ 437 void checkStaticMethod(jclass jclazz, jmethodID methodID) { 438 ScopedCheckJniThreadState ts(mEnv); 439 440 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(self(), jclazz); 441 const Method* method = (const Method*) methodID; 442 443 if (!dvmInstanceof(clazz, method->clazz)) { 444 ALOGW("JNI WARNING: can't call static %s.%s on class %s (%s)", 445 method->clazz->descriptor, method->name, clazz->descriptor, mFunctionName); 446 showLocation(); 447 // no abort? 448 } 449 } 450 451 /* 452 * Verify that "methodID" is appropriate for "jobj". 453 * 454 * Make sure the object is an instance of the method's declaring class. 455 * (Note the methodID might point to a declaration in an interface; this 456 * will be handled automatically by the instanceof check.) 457 */ 458 void checkVirtualMethod(jobject jobj, jmethodID methodID) { 459 ScopedCheckJniThreadState ts(mEnv); 460 461 Object* obj = dvmDecodeIndirectRef(self(), jobj); 462 const Method* method = (const Method*) methodID; 463 464 if (!dvmInstanceof(obj->clazz, method->clazz)) { 465 ALOGW("JNI WARNING: can't call %s.%s on instance of %s (%s)", 466 method->clazz->descriptor, method->name, obj->clazz->descriptor, mFunctionName); 467 showLocation(); 468 abortMaybe(); 469 } 470 } 471 472 /** 473 * The format string is a sequence of the following characters, 474 * and must be followed by arguments of the corresponding types 475 * in the same order. 476 * 477 * Java primitive types: 478 * B - jbyte 479 * C - jchar 480 * D - jdouble 481 * F - jfloat 482 * I - jint 483 * J - jlong 484 * S - jshort 485 * Z - jboolean (shown as true and false) 486 * V - void 487 * 488 * Java reference types: 489 * L - jobject 490 * a - jarray 491 * c - jclass 492 * s - jstring 493 * 494 * JNI types: 495 * b - jboolean (shown as JNI_TRUE and JNI_FALSE) 496 * f - jfieldID 497 * m - jmethodID 498 * p - void* 499 * r - jint (for release mode arguments) 500 * t - thread args (for AttachCurrentThread) 501 * u - const char* (modified UTF-8) 502 * z - jsize (for lengths; use i if negative values are okay) 503 * v - JavaVM* 504 * E - JNIEnv* 505 * . - no argument; just print "..." (used for varargs JNI calls) 506 * 507 * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable. 508 */ 509 void check(bool entry, const char* fmt0, ...) { 510 va_list ap; 511 512 bool shouldTrace = false; 513 const Method* method = NULL; 514 if ((gDvm.jniTrace || gDvmJni.logThirdPartyJni) && mHasMethod) { 515 // We need to guard some of the invocation interface's calls: a bad caller might 516 // use DetachCurrentThread or GetEnv on a thread that's not yet attached. 517 if ((mFlags & kFlag_Invocation) == 0 || dvmThreadSelf() != NULL) { 518 method = dvmGetCurrentJNIMethod(); 519 } 520 } 521 if (method != NULL) { 522 // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages 523 // when a native method that matches the Xjnitrace argument calls a JNI function 524 // such as NewByteArray. 525 if (gDvm.jniTrace && strstr(method->clazz->descriptor, gDvm.jniTrace) != NULL) { 526 shouldTrace = true; 527 } 528 // If -Xjniopts:logThirdPartyJni is on, we want to log any JNI function calls 529 // made by a third-party native method. 530 if (gDvmJni.logThirdPartyJni) { 531 shouldTrace |= method->shouldTrace; 532 } 533 } 534 535 if (shouldTrace) { 536 va_start(ap, fmt0); 537 std::string msg; 538 for (const char* fmt = fmt0; *fmt;) { 539 char ch = *fmt++; 540 if (ch == 'B') { // jbyte 541 jbyte b = va_arg(ap, int); 542 if (b >= 0 && b < 10) { 543 StringAppendF(&msg, "%d", b); 544 } else { 545 StringAppendF(&msg, "%#x (%d)", b, b); 546 } 547 } else if (ch == 'C') { // jchar 548 jchar c = va_arg(ap, int); 549 if (c < 0x7f && c >= ' ') { 550 StringAppendF(&msg, "U+%x ('%c')", c, c); 551 } else { 552 StringAppendF(&msg, "U+%x", c); 553 } 554 } else if (ch == 'F' || ch == 'D') { // jfloat, jdouble 555 StringAppendF(&msg, "%g", va_arg(ap, double)); 556 } else if (ch == 'I' || ch == 'S') { // jint, jshort 557 StringAppendF(&msg, "%d", va_arg(ap, int)); 558 } else if (ch == 'J') { // jlong 559 StringAppendF(&msg, "%lld", va_arg(ap, jlong)); 560 } else if (ch == 'Z') { // jboolean 561 StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false"); 562 } else if (ch == 'V') { // void 563 msg += "void"; 564 } else if (ch == 'v') { // JavaVM* 565 JavaVM* vm = va_arg(ap, JavaVM*); 566 StringAppendF(&msg, "(JavaVM*)%p", vm); 567 } else if (ch == 'E') { // JNIEnv* 568 JNIEnv* env = va_arg(ap, JNIEnv*); 569 StringAppendF(&msg, "(JNIEnv*)%p", env); 570 } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring 571 // For logging purposes, these are identical. 572 jobject o = va_arg(ap, jobject); 573 if (o == NULL) { 574 msg += "NULL"; 575 } else { 576 StringAppendF(&msg, "%p", o); 577 } 578 } else if (ch == 'b') { // jboolean (JNI-style) 579 jboolean b = va_arg(ap, int); 580 msg += (b ? "JNI_TRUE" : "JNI_FALSE"); 581 } else if (ch == 'c') { // jclass 582 jclass jc = va_arg(ap, jclass); 583 Object* c = dvmDecodeIndirectRef(self(), jc); 584 if (c == NULL) { 585 msg += "NULL"; 586 } else if (c == kInvalidIndirectRefObject || !dvmIsHeapAddress(c)) { 587 StringAppendF(&msg, "%p(INVALID)", jc); 588 } else { 589 std::string className(dvmHumanReadableType(c)); 590 StringAppendF(&msg, "%s", className.c_str()); 591 if (!entry) { 592 StringAppendF(&msg, " (%p)", jc); 593 } 594 } 595 } else if (ch == 'f') { // jfieldID 596 jfieldID fid = va_arg(ap, jfieldID); 597 std::string name(dvmHumanReadableField((Field*) fid)); 598 StringAppendF(&msg, "%s", name.c_str()); 599 if (!entry) { 600 StringAppendF(&msg, " (%p)", fid); 601 } 602 } else if (ch == 'z') { // non-negative jsize 603 // You might expect jsize to be size_t, but it's not; it's the same as jint. 604 // We only treat this specially so we can do the non-negative check. 605 // TODO: maybe this wasn't worth it? 606 jint i = va_arg(ap, jint); 607 StringAppendF(&msg, "%d", i); 608 } else if (ch == 'm') { // jmethodID 609 jmethodID mid = va_arg(ap, jmethodID); 610 std::string name(dvmHumanReadableMethod((Method*) mid, true)); 611 StringAppendF(&msg, "%s", name.c_str()); 612 if (!entry) { 613 StringAppendF(&msg, " (%p)", mid); 614 } 615 } else if (ch == 'p' || ch == 't') { // void* ("pointer" or "thread args") 616 void* p = va_arg(ap, void*); 617 if (p == NULL) { 618 msg += "NULL"; 619 } else { 620 StringAppendF(&msg, "(void*) %p", p); 621 } 622 } else if (ch == 'r') { // jint (release mode) 623 jint releaseMode = va_arg(ap, jint); 624 if (releaseMode == 0) { 625 msg += "0"; 626 } else if (releaseMode == JNI_ABORT) { 627 msg += "JNI_ABORT"; 628 } else if (releaseMode == JNI_COMMIT) { 629 msg += "JNI_COMMIT"; 630 } else { 631 StringAppendF(&msg, "invalid release mode %d", releaseMode); 632 } 633 } else if (ch == 'u') { // const char* (modified UTF-8) 634 const char* utf = va_arg(ap, const char*); 635 if (utf == NULL) { 636 msg += "NULL"; 637 } else { 638 StringAppendF(&msg, "\"%s\"", utf); 639 } 640 } else if (ch == '.') { 641 msg += "..."; 642 } else { 643 ALOGE("unknown trace format specifier %c", ch); 644 dvmAbort(); 645 } 646 if (*fmt) { 647 StringAppendF(&msg, ", "); 648 } 649 } 650 va_end(ap); 651 652 if (entry) { 653 if (mHasMethod) { 654 std::string methodName(dvmHumanReadableMethod(method, false)); 655 ALOGI("JNI: %s -> %s(%s)", methodName.c_str(), mFunctionName, msg.c_str()); 656 mIndent = methodName.size() + 1; 657 } else { 658 ALOGI("JNI: -> %s(%s)", mFunctionName, msg.c_str()); 659 mIndent = 0; 660 } 661 } else { 662 ALOGI("JNI: %*s<- %s returned %s", mIndent, "", mFunctionName, msg.c_str()); 663 } 664 } 665 666 // We always do the thorough checks on entry, and never on exit... 667 if (entry) { 668 va_start(ap, fmt0); 669 for (const char* fmt = fmt0; *fmt; ++fmt) { 670 char ch = *fmt; 671 if (ch == 'a') { 672 checkArray(va_arg(ap, jarray)); 673 } else if (ch == 'c') { 674 checkClass(va_arg(ap, jclass)); 675 } else if (ch == 'L') { 676 checkObject(va_arg(ap, jobject)); 677 } else if (ch == 'r') { 678 checkReleaseMode(va_arg(ap, jint)); 679 } else if (ch == 's') { 680 checkString(va_arg(ap, jstring)); 681 } else if (ch == 't') { 682 checkThreadArgs(va_arg(ap, void*)); 683 } else if (ch == 'u') { 684 if ((mFlags & kFlag_Release) != 0) { 685 checkNonNull(va_arg(ap, const char*)); 686 } else { 687 bool nullable = ((mFlags & kFlag_NullableUtf) != 0); 688 checkUtfString(va_arg(ap, const char*), nullable); 689 } 690 } else if (ch == 'z') { 691 checkLengthPositive(va_arg(ap, jsize)); 692 } else if (strchr("BCISZbfmpEv", ch) != NULL) { 693 va_arg(ap, int); // Skip this argument. 694 } else if (ch == 'D' || ch == 'F') { 695 va_arg(ap, double); // Skip this argument. 696 } else if (ch == 'J') { 697 va_arg(ap, long); // Skip this argument. 698 } else if (ch == '.') { 699 } else { 700 ALOGE("unknown check format specifier %c", ch); 701 dvmAbort(); 702 } 703 } 704 va_end(ap); 705 } 706 } 707 708 // Only safe after checkThread returns. 709 Thread* self() { 710 return ((JNIEnvExt*) mEnv)->self; 711 } 712 713 private: 714 JNIEnv* mEnv; 715 const char* mFunctionName; 716 int mFlags; 717 bool mHasMethod; 718 size_t mIndent; 719 720 void init(JNIEnv* env, int flags, const char* functionName, bool hasMethod) { 721 mEnv = env; 722 mFlags = flags; 723 724 // Use +6 to drop the leading "Check_"... 725 mFunctionName = functionName + 6; 726 727 // Set "hasMethod" to true if we have a valid thread with a method pointer. 728 // We won't have one before attaching a thread, after detaching a thread, or 729 // after destroying the VM. 730 mHasMethod = hasMethod; 731 } 732 733 /* 734 * Verify that "array" is non-NULL and points to an Array object. 735 * 736 * Since we're dealing with objects, switch to "running" mode. 737 */ 738 void checkArray(jarray jarr) { 739 if (jarr == NULL) { 740 ALOGW("JNI WARNING: %s received null array", mFunctionName); 741 showLocation(); 742 abortMaybe(); 743 return; 744 } 745 746 ScopedCheckJniThreadState ts(mEnv); 747 bool printWarn = false; 748 749 Object* obj = dvmDecodeIndirectRef(self(), jarr); 750 if (!dvmIsHeapAddress(obj)) { 751 ALOGW("JNI WARNING: %s: jarray is an invalid %s reference (%p)", 752 mFunctionName, indirectRefKindName(jarr), jarr); 753 printWarn = true; 754 } else if (obj->clazz->descriptor[0] != '[') { 755 ALOGW("JNI WARNING: %s: jarray arg has wrong type (expected array, got %s)", 756 mFunctionName, obj->clazz->descriptor); 757 printWarn = true; 758 } 759 760 if (printWarn) { 761 showLocation(); 762 abortMaybe(); 763 } 764 } 765 766 void checkClass(jclass c) { 767 checkInstance(c, gDvm.classJavaLangClass, "jclass"); 768 } 769 770 void checkLengthPositive(jsize length) { 771 if (length < 0) { 772 ALOGW("JNI WARNING: negative jsize (%s)", mFunctionName); 773 abortMaybe(); 774 } 775 } 776 777 /* 778 * Verify that "jobj" is a valid object, and that it's an object that JNI 779 * is allowed to know about. We allow NULL references. 780 * 781 * Switches to "running" mode before performing checks. 782 */ 783 void checkObject(jobject jobj) { 784 if (jobj == NULL) { 785 return; 786 } 787 788 ScopedCheckJniThreadState ts(mEnv); 789 790 bool printWarn = false; 791 if (dvmGetJNIRefType(self(), jobj) == JNIInvalidRefType) { 792 ALOGW("JNI WARNING: %p is not a valid JNI reference (%s)", jobj, mFunctionName); 793 printWarn = true; 794 } else { 795 Object* obj = dvmDecodeIndirectRef(self(), jobj); 796 if (obj == kInvalidIndirectRefObject) { 797 ALOGW("JNI WARNING: native code passing in invalid reference %p (%s)", 798 jobj, mFunctionName); 799 printWarn = true; 800 } else if (obj != NULL && !dvmIsHeapAddress(obj)) { 801 // TODO: when we remove workAroundAppJniBugs, this should be impossible. 802 ALOGW("JNI WARNING: native code passing in reference to invalid object %p %p (%s)", 803 jobj, obj, mFunctionName); 804 printWarn = true; 805 } 806 } 807 808 if (printWarn) { 809 showLocation(); 810 abortMaybe(); 811 } 812 } 813 814 /* 815 * Verify that the "mode" argument passed to a primitive array Release 816 * function is one of the valid values. 817 */ 818 void checkReleaseMode(jint mode) { 819 if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) { 820 ALOGW("JNI WARNING: bad value for mode (%d) (%s)", mode, mFunctionName); 821 abortMaybe(); 822 } 823 } 824 825 void checkString(jstring s) { 826 checkInstance(s, gDvm.classJavaLangString, "jstring"); 827 } 828 829 void checkThreadArgs(void* thread_args) { 830 JavaVMAttachArgs* args = static_cast<JavaVMAttachArgs*>(thread_args); 831 if (args != NULL && args->version < JNI_VERSION_1_2) { 832 ALOGW("JNI WARNING: bad value for JNI version (%d) (%s)", args->version, mFunctionName); 833 abortMaybe(); 834 } 835 } 836 837 void checkThread(int flags) { 838 // Get the *correct* JNIEnv by going through our TLS pointer. 839 JNIEnvExt* threadEnv = dvmGetJNIEnvForThread(); 840 841 /* 842 * Verify that the current thread is (a) attached and (b) associated with 843 * this particular instance of JNIEnv. 844 */ 845 bool printWarn = false; 846 if (threadEnv == NULL) { 847 ALOGE("JNI ERROR: non-VM thread making JNI call (%s)", mFunctionName); 848 // don't set printWarn -- it'll try to call showLocation() 849 dvmAbort(); 850 } else if ((JNIEnvExt*) mEnv != threadEnv) { 851 if (dvmThreadSelf()->threadId != threadEnv->envThreadId) { 852 ALOGE("JNI: threadEnv != thread->env? (%s)", mFunctionName); 853 dvmAbort(); 854 } 855 856 ALOGW("JNI WARNING: threadid=%d using env from threadid=%d (%s)", 857 threadEnv->envThreadId, ((JNIEnvExt*) mEnv)->envThreadId, mFunctionName); 858 printWarn = true; 859 860 // If we're keeping broken code limping along, we need to suppress the abort... 861 if (gDvmJni.workAroundAppJniBugs) { 862 printWarn = false; 863 } 864 865 /* this is a bad idea -- need to throw as we exit, or abort func */ 866 //dvmThrowRuntimeException("invalid use of JNI env ptr"); 867 } else if (((JNIEnvExt*) mEnv)->self != dvmThreadSelf()) { 868 /* correct JNIEnv*; make sure the "self" pointer is correct */ 869 ALOGE("JNI ERROR: env->self != thread-self (%p vs. %p) (%s)", 870 ((JNIEnvExt*) mEnv)->self, dvmThreadSelf(), mFunctionName); 871 dvmAbort(); 872 } 873 874 /* 875 * Verify that, if this thread previously made a critical "get" call, we 876 * do the corresponding "release" call before we try anything else. 877 */ 878 switch (flags & kFlag_CritMask) { 879 case kFlag_CritOkay: // okay to call this method 880 break; 881 case kFlag_CritBad: // not okay to call 882 if (threadEnv->critical) { 883 ALOGW("JNI WARNING: threadid=%d using JNI after critical get (%s)", 884 threadEnv->envThreadId, mFunctionName); 885 printWarn = true; 886 } 887 break; 888 case kFlag_CritGet: // this is a "get" call 889 /* don't check here; we allow nested gets */ 890 threadEnv->critical++; 891 break; 892 case kFlag_CritRelease: // this is a "release" call 893 threadEnv->critical--; 894 if (threadEnv->critical < 0) { 895 ALOGW("JNI WARNING: threadid=%d called too many critical releases (%s)", 896 threadEnv->envThreadId, mFunctionName); 897 printWarn = true; 898 } 899 break; 900 default: 901 assert(false); 902 } 903 904 /* 905 * Verify that, if an exception has been raised, the native code doesn't 906 * make any JNI calls other than the Exception* methods. 907 */ 908 bool printException = false; 909 if ((flags & kFlag_ExcepOkay) == 0 && dvmCheckException(dvmThreadSelf())) { 910 ALOGW("JNI WARNING: JNI function %s called with exception pending", mFunctionName); 911 printWarn = true; 912 printException = true; 913 } 914 915 if (printWarn) { 916 showLocation(); 917 } 918 if (printException) { 919 ALOGW("Pending exception is:"); 920 dvmLogExceptionStackTrace(); 921 } 922 if (printWarn) { 923 abortMaybe(); 924 } 925 } 926 927 /* 928 * Verify that "bytes" points to valid "modified UTF-8" data. 929 */ 930 void checkUtfString(const char* bytes, bool nullable) { 931 if (bytes == NULL) { 932 if (!nullable) { 933 ALOGW("JNI WARNING: non-nullable const char* was NULL (%s)", mFunctionName); 934 showLocation(); 935 abortMaybe(); 936 } 937 return; 938 } 939 940 const char* errorKind = NULL; 941 u1 utf8 = checkUtfBytes(bytes, &errorKind); 942 if (errorKind != NULL) { 943 ALOGW("JNI WARNING: %s input is not valid Modified UTF-8: illegal %s byte %#x", 944 mFunctionName, errorKind, utf8); 945 ALOGW(" string: '%s'", bytes); 946 showLocation(); 947 abortMaybe(); 948 } 949 } 950 951 /* 952 * Verify that "jobj" is a valid non-NULL object reference, and points to 953 * an instance of expectedClass. 954 * 955 * Because we're looking at an object on the GC heap, we have to switch 956 * to "running" mode before doing the checks. 957 */ 958 void checkInstance(jobject jobj, ClassObject* expectedClass, const char* argName) { 959 if (jobj == NULL) { 960 ALOGW("JNI WARNING: received null %s (%s)", argName, mFunctionName); 961 showLocation(); 962 abortMaybe(); 963 return; 964 } 965 966 ScopedCheckJniThreadState ts(mEnv); 967 bool printWarn = false; 968 969 Object* obj = dvmDecodeIndirectRef(self(), jobj); 970 if (!dvmIsHeapAddress(obj)) { 971 ALOGW("JNI WARNING: %s is an invalid %s reference (%p) (%s)", 972 argName, indirectRefKindName(jobj), jobj, mFunctionName); 973 printWarn = true; 974 } else if (obj->clazz != expectedClass) { 975 ALOGW("JNI WARNING: %s arg has wrong type (expected %s, got %s) (%s)", 976 argName, expectedClass->descriptor, obj->clazz->descriptor, mFunctionName); 977 printWarn = true; 978 } 979 980 if (printWarn) { 981 showLocation(); 982 abortMaybe(); 983 } 984 } 985 986 static u1 checkUtfBytes(const char* bytes, const char** errorKind) { 987 while (*bytes != '\0') { 988 u1 utf8 = *(bytes++); 989 // Switch on the high four bits. 990 switch (utf8 >> 4) { 991 case 0x00: 992 case 0x01: 993 case 0x02: 994 case 0x03: 995 case 0x04: 996 case 0x05: 997 case 0x06: 998 case 0x07: 999 // Bit pattern 0xxx. No need for any extra bytes. 1000 break; 1001 case 0x08: 1002 case 0x09: 1003 case 0x0a: 1004 case 0x0b: 1005 case 0x0f: 1006 /* 1007 * Bit pattern 10xx or 1111, which are illegal start bytes. 1008 * Note: 1111 is valid for normal UTF-8, but not the 1009 * modified UTF-8 used here. 1010 */ 1011 *errorKind = "start"; 1012 return utf8; 1013 case 0x0e: 1014 // Bit pattern 1110, so there are two additional bytes. 1015 utf8 = *(bytes++); 1016 if ((utf8 & 0xc0) != 0x80) { 1017 *errorKind = "continuation"; 1018 return utf8; 1019 } 1020 // Fall through to take care of the final byte. 1021 case 0x0c: 1022 case 0x0d: 1023 // Bit pattern 110x, so there is one additional byte. 1024 utf8 = *(bytes++); 1025 if ((utf8 & 0xc0) != 0x80) { 1026 *errorKind = "continuation"; 1027 return utf8; 1028 } 1029 break; 1030 } 1031 } 1032 return 0; 1033 } 1034 1035 /** 1036 * Returns a human-readable name for the given primitive type. 1037 */ 1038 static const char* primitiveTypeToName(PrimitiveType primType) { 1039 switch (primType) { 1040 case PRIM_VOID: return "void"; 1041 case PRIM_BOOLEAN: return "boolean"; 1042 case PRIM_BYTE: return "byte"; 1043 case PRIM_SHORT: return "short"; 1044 case PRIM_CHAR: return "char"; 1045 case PRIM_INT: return "int"; 1046 case PRIM_LONG: return "long"; 1047 case PRIM_FLOAT: return "float"; 1048 case PRIM_DOUBLE: return "double"; 1049 case PRIM_NOT: return "Object/array"; 1050 default: return "???"; 1051 } 1052 } 1053 1054 void showLocation() { 1055 const Method* method = dvmGetCurrentJNIMethod(); 1056 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 1057 ALOGW(" in %s.%s:%s (%s)", method->clazz->descriptor, method->name, desc, mFunctionName); 1058 free(desc); 1059 } 1060 1061 // Disallow copy and assignment. 1062 ScopedCheck(const ScopedCheck&); 1063 void operator=(const ScopedCheck&); 1064 }; 1065 1066 /* 1067 * =========================================================================== 1068 * Guarded arrays 1069 * =========================================================================== 1070 */ 1071 1072 #define kGuardLen 512 /* must be multiple of 2 */ 1073 #define kGuardPattern 0xd5e3 /* uncommon values; d5e3d5e3 invalid addr */ 1074 #define kGuardMagic 0xffd5aa96 1075 1076 /* this gets tucked in at the start of the buffer; struct size must be even */ 1077 struct GuardedCopy { 1078 u4 magic; 1079 uLong adler; 1080 size_t originalLen; 1081 const void* originalPtr; 1082 1083 /* find the GuardedCopy given the pointer into the "live" data */ 1084 static inline const GuardedCopy* fromData(const void* dataBuf) { 1085 return reinterpret_cast<const GuardedCopy*>(actualBuffer(dataBuf)); 1086 } 1087 1088 /* 1089 * Create an over-sized buffer to hold the contents of "buf". Copy it in, 1090 * filling in the area around it with guard data. 1091 * 1092 * We use a 16-bit pattern to make a rogue memset less likely to elude us. 1093 */ 1094 static void* create(const void* buf, size_t len, bool modOkay) { 1095 size_t newLen = actualLength(len); 1096 u1* newBuf = debugAlloc(newLen); 1097 1098 /* fill it in with a pattern */ 1099 u2* pat = (u2*) newBuf; 1100 for (size_t i = 0; i < newLen / 2; i++) { 1101 *pat++ = kGuardPattern; 1102 } 1103 1104 /* copy the data in; note "len" could be zero */ 1105 memcpy(newBuf + kGuardLen / 2, buf, len); 1106 1107 /* if modification is not expected, grab a checksum */ 1108 uLong adler = 0; 1109 if (!modOkay) { 1110 adler = adler32(0L, Z_NULL, 0); 1111 adler = adler32(adler, (const Bytef*)buf, len); 1112 *(uLong*)newBuf = adler; 1113 } 1114 1115 GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf); 1116 pExtra->magic = kGuardMagic; 1117 pExtra->adler = adler; 1118 pExtra->originalPtr = buf; 1119 pExtra->originalLen = len; 1120 1121 return newBuf + kGuardLen / 2; 1122 } 1123 1124 /* 1125 * Free up the guard buffer, scrub it, and return the original pointer. 1126 */ 1127 static void* destroy(void* dataBuf) { 1128 const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf); 1129 void* originalPtr = (void*) pExtra->originalPtr; 1130 size_t len = pExtra->originalLen; 1131 debugFree(dataBuf, len); 1132 return originalPtr; 1133 } 1134 1135 /* 1136 * Verify the guard area and, if "modOkay" is false, that the data itself 1137 * has not been altered. 1138 * 1139 * The caller has already checked that "dataBuf" is non-NULL. 1140 */ 1141 static bool check(const void* dataBuf, bool modOkay) { 1142 static const u4 kMagicCmp = kGuardMagic; 1143 const u1* fullBuf = actualBuffer(dataBuf); 1144 const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf); 1145 1146 /* 1147 * Before we do anything with "pExtra", check the magic number. We 1148 * do the check with memcmp rather than "==" in case the pointer is 1149 * unaligned. If it points to completely bogus memory we're going 1150 * to crash, but there's no easy way around that. 1151 */ 1152 if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) { 1153 u1 buf[4]; 1154 memcpy(buf, &pExtra->magic, 4); 1155 ALOGE("JNI: guard magic does not match (found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?", 1156 buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */ 1157 return false; 1158 } 1159 1160 size_t len = pExtra->originalLen; 1161 1162 /* check bottom half of guard; skip over optional checksum storage */ 1163 const u2* pat = (u2*) fullBuf; 1164 for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) { 1165 if (pat[i] != kGuardPattern) { 1166 ALOGE("JNI: guard pattern(1) disturbed at %p + %d", fullBuf, i*2); 1167 return false; 1168 } 1169 } 1170 1171 int offset = kGuardLen / 2 + len; 1172 if (offset & 0x01) { 1173 /* odd byte; expected value depends on endian-ness of host */ 1174 const u2 patSample = kGuardPattern; 1175 if (fullBuf[offset] != ((const u1*) &patSample)[1]) { 1176 ALOGE("JNI: guard pattern disturbed in odd byte after %p (+%d) 0x%02x 0x%02x", 1177 fullBuf, offset, fullBuf[offset], ((const u1*) &patSample)[1]); 1178 return false; 1179 } 1180 offset++; 1181 } 1182 1183 /* check top half of guard */ 1184 pat = (u2*) (fullBuf + offset); 1185 for (size_t i = 0; i < kGuardLen / 4; i++) { 1186 if (pat[i] != kGuardPattern) { 1187 ALOGE("JNI: guard pattern(2) disturbed at %p + %d", fullBuf, offset + i*2); 1188 return false; 1189 } 1190 } 1191 1192 /* 1193 * If modification is not expected, verify checksum. Strictly speaking 1194 * this is wrong: if we told the client that we made a copy, there's no 1195 * reason they can't alter the buffer. 1196 */ 1197 if (!modOkay) { 1198 uLong adler = adler32(0L, Z_NULL, 0); 1199 adler = adler32(adler, (const Bytef*)dataBuf, len); 1200 if (pExtra->adler != adler) { 1201 ALOGE("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p", 1202 pExtra->adler, adler, dataBuf); 1203 return false; 1204 } 1205 } 1206 1207 return true; 1208 } 1209 1210 private: 1211 static u1* debugAlloc(size_t len) { 1212 void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); 1213 if (result == MAP_FAILED) { 1214 ALOGE("GuardedCopy::create mmap(%d) failed: %s", len, strerror(errno)); 1215 dvmAbort(); 1216 } 1217 return reinterpret_cast<u1*>(result); 1218 } 1219 1220 static void debugFree(void* dataBuf, size_t len) { 1221 u1* fullBuf = actualBuffer(dataBuf); 1222 size_t totalByteCount = actualLength(len); 1223 // TODO: we could mprotect instead, and keep the allocation around for a while. 1224 // This would be even more expensive, but it might catch more errors. 1225 // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) { 1226 // ALOGW("mprotect(PROT_NONE) failed: %s", strerror(errno)); 1227 // } 1228 if (munmap(fullBuf, totalByteCount) != 0) { 1229 ALOGW("munmap failed: %s", strerror(errno)); 1230 dvmAbort(); 1231 } 1232 } 1233 1234 static const u1* actualBuffer(const void* dataBuf) { 1235 return reinterpret_cast<const u1*>(dataBuf) - kGuardLen / 2; 1236 } 1237 1238 static u1* actualBuffer(void* dataBuf) { 1239 return reinterpret_cast<u1*>(dataBuf) - kGuardLen / 2; 1240 } 1241 1242 // Underlying length of a user allocation of 'length' bytes. 1243 static size_t actualLength(size_t length) { 1244 return (length + kGuardLen + 1) & ~0x01; 1245 } 1246 }; 1247 1248 /* 1249 * Return the width, in bytes, of a primitive type. 1250 */ 1251 static int dvmPrimitiveTypeWidth(PrimitiveType primType) { 1252 switch (primType) { 1253 case PRIM_BOOLEAN: return 1; 1254 case PRIM_BYTE: return 1; 1255 case PRIM_SHORT: return 2; 1256 case PRIM_CHAR: return 2; 1257 case PRIM_INT: return 4; 1258 case PRIM_LONG: return 8; 1259 case PRIM_FLOAT: return 4; 1260 case PRIM_DOUBLE: return 8; 1261 case PRIM_VOID: 1262 default: { 1263 assert(false); 1264 return -1; 1265 } 1266 } 1267 } 1268 1269 /* 1270 * Create a guarded copy of a primitive array. Modifications to the copied 1271 * data are allowed. Returns a pointer to the copied data. 1272 */ 1273 static void* createGuardedPACopy(JNIEnv* env, const jarray jarr, jboolean* isCopy) { 1274 ScopedCheckJniThreadState ts(env); 1275 1276 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(dvmThreadSelf(), jarr); 1277 PrimitiveType primType = arrObj->clazz->elementClass->primitiveType; 1278 int len = arrObj->length * dvmPrimitiveTypeWidth(primType); 1279 void* result = GuardedCopy::create(arrObj->contents, len, true); 1280 if (isCopy != NULL) { 1281 *isCopy = JNI_TRUE; 1282 } 1283 return result; 1284 } 1285 1286 /* 1287 * Perform the array "release" operation, which may or may not copy data 1288 * back into the VM, and may or may not release the underlying storage. 1289 */ 1290 static void* releaseGuardedPACopy(JNIEnv* env, jarray jarr, void* dataBuf, int mode) { 1291 ScopedCheckJniThreadState ts(env); 1292 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(dvmThreadSelf(), jarr); 1293 1294 if (!GuardedCopy::check(dataBuf, true)) { 1295 ALOGE("JNI: failed guarded copy check in releaseGuardedPACopy"); 1296 abortMaybe(); 1297 return NULL; 1298 } 1299 1300 if (mode != JNI_ABORT) { 1301 size_t len = GuardedCopy::fromData(dataBuf)->originalLen; 1302 memcpy(arrObj->contents, dataBuf, len); 1303 } 1304 1305 u1* result = NULL; 1306 if (mode != JNI_COMMIT) { 1307 result = (u1*) GuardedCopy::destroy(dataBuf); 1308 } else { 1309 result = (u1*) (void*) GuardedCopy::fromData(dataBuf)->originalPtr; 1310 } 1311 1312 /* pointer is to the array contents; back up to the array object */ 1313 result -= OFFSETOF_MEMBER(ArrayObject, contents); 1314 return result; 1315 } 1316 1317 1318 /* 1319 * =========================================================================== 1320 * JNI functions 1321 * =========================================================================== 1322 */ 1323 1324 #define CHECK_JNI_ENTRY(flags, types, args...) \ 1325 ScopedCheck sc(env, flags, __FUNCTION__); \ 1326 sc.check(true, types, ##args) 1327 1328 #define CHECK_JNI_EXIT(type, exp) ({ \ 1329 typeof (exp) _rc = (exp); \ 1330 sc.check(false, type, _rc); \ 1331 _rc; }) 1332 #define CHECK_JNI_EXIT_VOID() \ 1333 sc.check(false, "V") 1334 1335 static jint Check_GetVersion(JNIEnv* env) { 1336 CHECK_JNI_ENTRY(kFlag_Default, "E", env); 1337 return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env)); 1338 } 1339 1340 static jclass Check_DefineClass(JNIEnv* env, const char* name, jobject loader, 1341 const jbyte* buf, jsize bufLen) 1342 { 1343 CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen); 1344 sc.checkClassName(name); 1345 return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen)); 1346 } 1347 1348 static jclass Check_FindClass(JNIEnv* env, const char* name) { 1349 CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name); 1350 sc.checkClassName(name); 1351 return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name)); 1352 } 1353 1354 static jclass Check_GetSuperclass(JNIEnv* env, jclass clazz) { 1355 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz); 1356 return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, clazz)); 1357 } 1358 1359 static jboolean Check_IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2) { 1360 CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, clazz1, clazz2); 1361 return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, clazz1, clazz2)); 1362 } 1363 1364 static jmethodID Check_FromReflectedMethod(JNIEnv* env, jobject method) { 1365 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method); 1366 // TODO: check that 'field' is a java.lang.reflect.Method. 1367 return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method)); 1368 } 1369 1370 static jfieldID Check_FromReflectedField(JNIEnv* env, jobject field) { 1371 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field); 1372 // TODO: check that 'field' is a java.lang.reflect.Field. 1373 return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field)); 1374 } 1375 1376 static jobject Check_ToReflectedMethod(JNIEnv* env, jclass cls, 1377 jmethodID methodID, jboolean isStatic) 1378 { 1379 CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, methodID, isStatic); 1380 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, methodID, isStatic)); 1381 } 1382 1383 static jobject Check_ToReflectedField(JNIEnv* env, jclass cls, 1384 jfieldID fieldID, jboolean isStatic) 1385 { 1386 CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fieldID, isStatic); 1387 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fieldID, isStatic)); 1388 } 1389 1390 static jint Check_Throw(JNIEnv* env, jthrowable obj) { 1391 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1392 // TODO: check that 'obj' is a java.lang.Throwable. 1393 return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj)); 1394 } 1395 1396 static jint Check_ThrowNew(JNIEnv* env, jclass clazz, const char* message) { 1397 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, clazz, message); 1398 return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, clazz, message)); 1399 } 1400 1401 static jthrowable Check_ExceptionOccurred(JNIEnv* env) { 1402 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env); 1403 return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env)); 1404 } 1405 1406 static void Check_ExceptionDescribe(JNIEnv* env) { 1407 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env); 1408 baseEnv(env)->ExceptionDescribe(env); 1409 CHECK_JNI_EXIT_VOID(); 1410 } 1411 1412 static void Check_ExceptionClear(JNIEnv* env) { 1413 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env); 1414 baseEnv(env)->ExceptionClear(env); 1415 CHECK_JNI_EXIT_VOID(); 1416 } 1417 1418 static void Check_FatalError(JNIEnv* env, const char* msg) { 1419 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg); 1420 baseEnv(env)->FatalError(env, msg); 1421 CHECK_JNI_EXIT_VOID(); 1422 } 1423 1424 static jint Check_PushLocalFrame(JNIEnv* env, jint capacity) { 1425 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity); 1426 return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity)); 1427 } 1428 1429 static jobject Check_PopLocalFrame(JNIEnv* env, jobject res) { 1430 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res); 1431 return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res)); 1432 } 1433 1434 static jobject Check_NewGlobalRef(JNIEnv* env, jobject obj) { 1435 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1436 return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj)); 1437 } 1438 1439 static void Check_DeleteGlobalRef(JNIEnv* env, jobject globalRef) { 1440 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef); 1441 if (globalRef != NULL && dvmGetJNIRefType(sc.self(), globalRef) != JNIGlobalRefType) { 1442 ALOGW("JNI WARNING: DeleteGlobalRef on non-global %p (type=%d)", 1443 globalRef, dvmGetJNIRefType(sc.self(), globalRef)); 1444 abortMaybe(); 1445 } else { 1446 baseEnv(env)->DeleteGlobalRef(env, globalRef); 1447 CHECK_JNI_EXIT_VOID(); 1448 } 1449 } 1450 1451 static jobject Check_NewLocalRef(JNIEnv* env, jobject ref) { 1452 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref); 1453 return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref)); 1454 } 1455 1456 static void Check_DeleteLocalRef(JNIEnv* env, jobject localRef) { 1457 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef); 1458 if (localRef != NULL && dvmGetJNIRefType(sc.self(), localRef) != JNILocalRefType) { 1459 ALOGW("JNI WARNING: DeleteLocalRef on non-local %p (type=%d)", 1460 localRef, dvmGetJNIRefType(sc.self(), localRef)); 1461 abortMaybe(); 1462 } else { 1463 baseEnv(env)->DeleteLocalRef(env, localRef); 1464 CHECK_JNI_EXIT_VOID(); 1465 } 1466 } 1467 1468 static jint Check_EnsureLocalCapacity(JNIEnv *env, jint capacity) { 1469 CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity); 1470 return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity)); 1471 } 1472 1473 static jboolean Check_IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) { 1474 CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2); 1475 return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2)); 1476 } 1477 1478 static jobject Check_AllocObject(JNIEnv* env, jclass clazz) { 1479 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz); 1480 return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, clazz)); 1481 } 1482 1483 static jobject Check_NewObject(JNIEnv* env, jclass clazz, jmethodID methodID, ...) { 1484 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); 1485 va_list args; 1486 va_start(args, methodID); 1487 jobject result = baseEnv(env)->NewObjectV(env, clazz, methodID, args); 1488 va_end(args); 1489 return CHECK_JNI_EXIT("L", result); 1490 } 1491 1492 static jobject Check_NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID, va_list args) { 1493 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); 1494 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, clazz, methodID, args)); 1495 } 1496 1497 static jobject Check_NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID, jvalue* args) { 1498 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); 1499 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, clazz, methodID, args)); 1500 } 1501 1502 static jclass Check_GetObjectClass(JNIEnv* env, jobject obj) { 1503 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1504 return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj)); 1505 } 1506 1507 static jboolean Check_IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) { 1508 CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, clazz); 1509 return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, clazz)); 1510 } 1511 1512 static jmethodID Check_GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) { 1513 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1514 return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, clazz, name, sig)); 1515 } 1516 1517 static jfieldID Check_GetFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) { 1518 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1519 return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, clazz, name, sig)); 1520 } 1521 1522 static jmethodID Check_GetStaticMethodID(JNIEnv* env, jclass clazz, 1523 const char* name, const char* sig) 1524 { 1525 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1526 return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, clazz, name, sig)); 1527 } 1528 1529 static jfieldID Check_GetStaticFieldID(JNIEnv* env, jclass clazz, 1530 const char* name, const char* sig) 1531 { 1532 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1533 return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, clazz, name, sig)); 1534 } 1535 1536 #define FIELD_ACCESSORS(_ctype, _jname, _ftype, _type) \ 1537 static _ctype Check_GetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fieldID) { \ 1538 CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, clazz, fieldID); \ 1539 sc.checkStaticFieldID(clazz, fieldID); \ 1540 sc.checkFieldTypeForGet(fieldID, _type, true); \ 1541 return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, clazz, fieldID)); \ 1542 } \ 1543 static _ctype Check_Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fieldID) { \ 1544 CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fieldID); \ 1545 sc.checkInstanceFieldID(obj, fieldID); \ 1546 sc.checkFieldTypeForGet(fieldID, _type, false); \ 1547 return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fieldID)); \ 1548 } \ 1549 static void Check_SetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fieldID, _ctype value) { \ 1550 CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, clazz, fieldID, value); \ 1551 sc.checkStaticFieldID(clazz, fieldID); \ 1552 /* "value" arg only used when type == ref */ \ 1553 sc.checkFieldTypeForSet((jobject)(u4)value, fieldID, _ftype, true); \ 1554 baseEnv(env)->SetStatic##_jname##Field(env, clazz, fieldID, value); \ 1555 CHECK_JNI_EXIT_VOID(); \ 1556 } \ 1557 static void Check_Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fieldID, _ctype value) { \ 1558 CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fieldID, value); \ 1559 sc.checkInstanceFieldID(obj, fieldID); \ 1560 /* "value" arg only used when type == ref */ \ 1561 sc.checkFieldTypeForSet((jobject)(u4) value, fieldID, _ftype, false); \ 1562 baseEnv(env)->Set##_jname##Field(env, obj, fieldID, value); \ 1563 CHECK_JNI_EXIT_VOID(); \ 1564 } 1565 1566 FIELD_ACCESSORS(jobject, Object, PRIM_NOT, "L"); 1567 FIELD_ACCESSORS(jboolean, Boolean, PRIM_BOOLEAN, "Z"); 1568 FIELD_ACCESSORS(jbyte, Byte, PRIM_BYTE, "B"); 1569 FIELD_ACCESSORS(jchar, Char, PRIM_CHAR, "C"); 1570 FIELD_ACCESSORS(jshort, Short, PRIM_SHORT, "S"); 1571 FIELD_ACCESSORS(jint, Int, PRIM_INT, "I"); 1572 FIELD_ACCESSORS(jlong, Long, PRIM_LONG, "J"); 1573 FIELD_ACCESSORS(jfloat, Float, PRIM_FLOAT, "F"); 1574 FIELD_ACCESSORS(jdouble, Double, PRIM_DOUBLE, "D"); 1575 1576 #define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \ 1577 /* Virtual... */ \ 1578 static _ctype Check_Call##_jname##Method(JNIEnv* env, jobject obj, \ 1579 jmethodID methodID, ...) \ 1580 { \ 1581 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \ 1582 sc.checkSig(methodID, _retsig, false); \ 1583 sc.checkVirtualMethod(obj, methodID); \ 1584 _retdecl; \ 1585 va_list args; \ 1586 va_start(args, methodID); \ 1587 _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, methodID, args); \ 1588 va_end(args); \ 1589 _retok; \ 1590 } \ 1591 static _ctype Check_Call##_jname##MethodV(JNIEnv* env, jobject obj, \ 1592 jmethodID methodID, va_list args) \ 1593 { \ 1594 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \ 1595 sc.checkSig(methodID, _retsig, false); \ 1596 sc.checkVirtualMethod(obj, methodID); \ 1597 _retdecl; \ 1598 _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, methodID, args); \ 1599 _retok; \ 1600 } \ 1601 static _ctype Check_Call##_jname##MethodA(JNIEnv* env, jobject obj, \ 1602 jmethodID methodID, jvalue* args) \ 1603 { \ 1604 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \ 1605 sc.checkSig(methodID, _retsig, false); \ 1606 sc.checkVirtualMethod(obj, methodID); \ 1607 _retdecl; \ 1608 _retasgn baseEnv(env)->Call##_jname##MethodA(env, obj, methodID, args); \ 1609 _retok; \ 1610 } \ 1611 /* Non-virtual... */ \ 1612 static _ctype Check_CallNonvirtual##_jname##Method(JNIEnv* env, \ 1613 jobject obj, jclass clazz, jmethodID methodID, ...) \ 1614 { \ 1615 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \ 1616 sc.checkSig(methodID, _retsig, false); \ 1617 sc.checkVirtualMethod(obj, methodID); \ 1618 _retdecl; \ 1619 va_list args; \ 1620 va_start(args, methodID); \ 1621 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, methodID, args); \ 1622 va_end(args); \ 1623 _retok; \ 1624 } \ 1625 static _ctype Check_CallNonvirtual##_jname##MethodV(JNIEnv* env, \ 1626 jobject obj, jclass clazz, jmethodID methodID, va_list args) \ 1627 { \ 1628 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \ 1629 sc.checkSig(methodID, _retsig, false); \ 1630 sc.checkVirtualMethod(obj, methodID); \ 1631 _retdecl; \ 1632 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, methodID, args); \ 1633 _retok; \ 1634 } \ 1635 static _ctype Check_CallNonvirtual##_jname##MethodA(JNIEnv* env, \ 1636 jobject obj, jclass clazz, jmethodID methodID, jvalue* args) \ 1637 { \ 1638 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \ 1639 sc.checkSig(methodID, _retsig, false); \ 1640 sc.checkVirtualMethod(obj, methodID); \ 1641 _retdecl; \ 1642 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, clazz, methodID, args); \ 1643 _retok; \ 1644 } \ 1645 /* Static... */ \ 1646 static _ctype Check_CallStatic##_jname##Method(JNIEnv* env, \ 1647 jclass clazz, jmethodID methodID, ...) \ 1648 { \ 1649 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \ 1650 sc.checkSig(methodID, _retsig, true); \ 1651 sc.checkStaticMethod(clazz, methodID); \ 1652 _retdecl; \ 1653 va_list args; \ 1654 va_start(args, methodID); \ 1655 _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, methodID, args); \ 1656 va_end(args); \ 1657 _retok; \ 1658 } \ 1659 static _ctype Check_CallStatic##_jname##MethodV(JNIEnv* env, \ 1660 jclass clazz, jmethodID methodID, va_list args) \ 1661 { \ 1662 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \ 1663 sc.checkSig(methodID, _retsig, true); \ 1664 sc.checkStaticMethod(clazz, methodID); \ 1665 _retdecl; \ 1666 _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, methodID, args); \ 1667 _retok; \ 1668 } \ 1669 static _ctype Check_CallStatic##_jname##MethodA(JNIEnv* env, \ 1670 jclass clazz, jmethodID methodID, jvalue* args) \ 1671 { \ 1672 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \ 1673 sc.checkSig(methodID, _retsig, true); \ 1674 sc.checkStaticMethod(clazz, methodID); \ 1675 _retdecl; \ 1676 _retasgn baseEnv(env)->CallStatic##_jname##MethodA(env, clazz, methodID, args); \ 1677 _retok; \ 1678 } 1679 1680 #define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result) 1681 #define VOID_RETURN CHECK_JNI_EXIT_VOID() 1682 1683 CALL(jobject, Object, Object* result, result=(Object*), NON_VOID_RETURN("L", jobject), "L"); 1684 CALL(jboolean, Boolean, jboolean result, result=, NON_VOID_RETURN("Z", jboolean), "Z"); 1685 CALL(jbyte, Byte, jbyte result, result=, NON_VOID_RETURN("B", jbyte), "B"); 1686 CALL(jchar, Char, jchar result, result=, NON_VOID_RETURN("C", jchar), "C"); 1687 CALL(jshort, Short, jshort result, result=, NON_VOID_RETURN("S", jshort), "S"); 1688 CALL(jint, Int, jint result, result=, NON_VOID_RETURN("I", jint), "I"); 1689 CALL(jlong, Long, jlong result, result=, NON_VOID_RETURN("J", jlong), "J"); 1690 CALL(jfloat, Float, jfloat result, result=, NON_VOID_RETURN("F", jfloat), "F"); 1691 CALL(jdouble, Double, jdouble result, result=, NON_VOID_RETURN("D", jdouble), "D"); 1692 CALL(void, Void, , , VOID_RETURN, "V"); 1693 1694 static jstring Check_NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) { 1695 CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len); 1696 return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len)); 1697 } 1698 1699 static jsize Check_GetStringLength(JNIEnv* env, jstring string) { 1700 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string); 1701 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string)); 1702 } 1703 1704 static const jchar* Check_GetStringChars(JNIEnv* env, jstring string, jboolean* isCopy) { 1705 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy); 1706 const jchar* result = baseEnv(env)->GetStringChars(env, string, isCopy); 1707 if (gDvmJni.forceCopy && result != NULL) { 1708 ScopedCheckJniThreadState ts(env); 1709 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(dvmThreadSelf(), string); 1710 int byteCount = strObj->length() * 2; 1711 result = (const jchar*) GuardedCopy::create(result, byteCount, false); 1712 if (isCopy != NULL) { 1713 *isCopy = JNI_TRUE; 1714 } 1715 } 1716 return CHECK_JNI_EXIT("p", result); 1717 } 1718 1719 static void Check_ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) { 1720 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars); 1721 sc.checkNonNull(chars); 1722 if (gDvmJni.forceCopy) { 1723 if (!GuardedCopy::check(chars, false)) { 1724 ALOGE("JNI: failed guarded copy check in ReleaseStringChars"); 1725 abortMaybe(); 1726 return; 1727 } 1728 chars = (const jchar*) GuardedCopy::destroy((jchar*)chars); 1729 } 1730 baseEnv(env)->ReleaseStringChars(env, string, chars); 1731 CHECK_JNI_EXIT_VOID(); 1732 } 1733 1734 static jstring Check_NewStringUTF(JNIEnv* env, const char* bytes) { 1735 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string. 1736 return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes)); 1737 } 1738 1739 static jsize Check_GetStringUTFLength(JNIEnv* env, jstring string) { 1740 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string); 1741 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string)); 1742 } 1743 1744 static const char* Check_GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) { 1745 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy); 1746 const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy); 1747 if (gDvmJni.forceCopy && result != NULL) { 1748 result = (const char*) GuardedCopy::create(result, strlen(result) + 1, false); 1749 if (isCopy != NULL) { 1750 *isCopy = JNI_TRUE; 1751 } 1752 } 1753 return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string. 1754 } 1755 1756 static void Check_ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) { 1757 CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string. 1758 if (gDvmJni.forceCopy) { 1759 if (!GuardedCopy::check(utf, false)) { 1760 ALOGE("JNI: failed guarded copy check in ReleaseStringUTFChars"); 1761 abortMaybe(); 1762 return; 1763 } 1764 utf = (const char*) GuardedCopy::destroy((char*)utf); 1765 } 1766 baseEnv(env)->ReleaseStringUTFChars(env, string, utf); 1767 CHECK_JNI_EXIT_VOID(); 1768 } 1769 1770 static jsize Check_GetArrayLength(JNIEnv* env, jarray array) { 1771 CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array); 1772 return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array)); 1773 } 1774 1775 static jobjectArray Check_NewObjectArray(JNIEnv* env, jsize length, 1776 jclass elementClass, jobject initialElement) 1777 { 1778 CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement); 1779 return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement)); 1780 } 1781 1782 static jobject Check_GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) { 1783 CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index); 1784 return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index)); 1785 } 1786 1787 static void Check_SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) 1788 { 1789 CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value); 1790 baseEnv(env)->SetObjectArrayElement(env, array, index, value); 1791 CHECK_JNI_EXIT_VOID(); 1792 } 1793 1794 #define NEW_PRIMITIVE_ARRAY(_artype, _jname) \ 1795 static _artype Check_New##_jname##Array(JNIEnv* env, jsize length) { \ 1796 CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \ 1797 return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \ 1798 } 1799 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean); 1800 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte); 1801 NEW_PRIMITIVE_ARRAY(jcharArray, Char); 1802 NEW_PRIMITIVE_ARRAY(jshortArray, Short); 1803 NEW_PRIMITIVE_ARRAY(jintArray, Int); 1804 NEW_PRIMITIVE_ARRAY(jlongArray, Long); 1805 NEW_PRIMITIVE_ARRAY(jfloatArray, Float); 1806 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double); 1807 1808 1809 /* 1810 * Hack to allow forcecopy to work with jniGetNonMovableArrayElements. 1811 * The code deliberately uses an invalid sequence of operations, so we 1812 * need to pass it through unmodified. Review that code before making 1813 * any changes here. 1814 */ 1815 #define kNoCopyMagic 0xd5aab57f 1816 1817 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \ 1818 static _ctype* Check_Get##_jname##ArrayElements(JNIEnv* env, \ 1819 _ctype##Array array, jboolean* isCopy) \ 1820 { \ 1821 CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \ 1822 u4 noCopy = 0; \ 1823 if (gDvmJni.forceCopy && isCopy != NULL) { \ 1824 /* capture this before the base call tramples on it */ \ 1825 noCopy = *(u4*) isCopy; \ 1826 } \ 1827 _ctype* result = baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy); \ 1828 if (gDvmJni.forceCopy && result != NULL) { \ 1829 if (noCopy == kNoCopyMagic) { \ 1830 ALOGV("FC: not copying %p %x", array, noCopy); \ 1831 } else { \ 1832 result = (_ctype*) createGuardedPACopy(env, array, isCopy); \ 1833 } \ 1834 } \ 1835 return CHECK_JNI_EXIT("p", result); \ 1836 } 1837 1838 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \ 1839 static void Check_Release##_jname##ArrayElements(JNIEnv* env, \ 1840 _ctype##Array array, _ctype* elems, jint mode) \ 1841 { \ 1842 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \ 1843 sc.checkNonNull(elems); \ 1844 if (gDvmJni.forceCopy) { \ 1845 if ((uintptr_t)elems == kNoCopyMagic) { \ 1846 ALOGV("FC: not freeing %p", array); \ 1847 elems = NULL; /* base JNI call doesn't currently need */ \ 1848 } else { \ 1849 elems = (_ctype*) releaseGuardedPACopy(env, array, elems, mode); \ 1850 } \ 1851 } \ 1852 baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \ 1853 CHECK_JNI_EXIT_VOID(); \ 1854 } 1855 1856 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \ 1857 static void Check_Get##_jname##ArrayRegion(JNIEnv* env, \ 1858 _ctype##Array array, jsize start, jsize len, _ctype* buf) { \ 1859 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \ 1860 baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \ 1861 CHECK_JNI_EXIT_VOID(); \ 1862 } 1863 1864 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \ 1865 static void Check_Set##_jname##ArrayRegion(JNIEnv* env, \ 1866 _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \ 1867 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \ 1868 baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \ 1869 CHECK_JNI_EXIT_VOID(); \ 1870 } 1871 1872 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \ 1873 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \ 1874 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \ 1875 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \ 1876 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); 1877 1878 /* TODO: verify primitive array type matches call type */ 1879 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z'); 1880 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B'); 1881 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C'); 1882 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S'); 1883 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I'); 1884 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J'); 1885 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F'); 1886 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D'); 1887 1888 static jint Check_RegisterNatives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, 1889 jint nMethods) 1890 { 1891 CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, clazz, methods, nMethods); 1892 return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, clazz, methods, nMethods)); 1893 } 1894 1895 static jint Check_UnregisterNatives(JNIEnv* env, jclass clazz) { 1896 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz); 1897 return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, clazz)); 1898 } 1899 1900 static jint Check_MonitorEnter(JNIEnv* env, jobject obj) { 1901 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1902 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj)); 1903 } 1904 1905 static jint Check_MonitorExit(JNIEnv* env, jobject obj) { 1906 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj); 1907 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj)); 1908 } 1909 1910 static jint Check_GetJavaVM(JNIEnv *env, JavaVM **vm) { 1911 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm); 1912 return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm)); 1913 } 1914 1915 static void Check_GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) { 1916 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf); 1917 baseEnv(env)->GetStringRegion(env, str, start, len, buf); 1918 CHECK_JNI_EXIT_VOID(); 1919 } 1920 1921 static void Check_GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) { 1922 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf); 1923 baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf); 1924 CHECK_JNI_EXIT_VOID(); 1925 } 1926 1927 static void* Check_GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) { 1928 CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy); 1929 void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy); 1930 if (gDvmJni.forceCopy && result != NULL) { 1931 result = createGuardedPACopy(env, array, isCopy); 1932 } 1933 return CHECK_JNI_EXIT("p", result); 1934 } 1935 1936 static void Check_ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) 1937 { 1938 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode); 1939 sc.checkNonNull(carray); 1940 if (gDvmJni.forceCopy) { 1941 carray = releaseGuardedPACopy(env, array, carray, mode); 1942 } 1943 baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode); 1944 CHECK_JNI_EXIT_VOID(); 1945 } 1946 1947 static const jchar* Check_GetStringCritical(JNIEnv* env, jstring string, jboolean* isCopy) { 1948 CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, string, isCopy); 1949 const jchar* result = baseEnv(env)->GetStringCritical(env, string, isCopy); 1950 if (gDvmJni.forceCopy && result != NULL) { 1951 ScopedCheckJniThreadState ts(env); 1952 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(dvmThreadSelf(), string); 1953 int byteCount = strObj->length() * 2; 1954 result = (const jchar*) GuardedCopy::create(result, byteCount, false); 1955 if (isCopy != NULL) { 1956 *isCopy = JNI_TRUE; 1957 } 1958 } 1959 return CHECK_JNI_EXIT("p", result); 1960 } 1961 1962 static void Check_ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) { 1963 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray); 1964 sc.checkNonNull(carray); 1965 if (gDvmJni.forceCopy) { 1966 if (!GuardedCopy::check(carray, false)) { 1967 ALOGE("JNI: failed guarded copy check in ReleaseStringCritical"); 1968 abortMaybe(); 1969 return; 1970 } 1971 carray = (const jchar*) GuardedCopy::destroy((jchar*)carray); 1972 } 1973 baseEnv(env)->ReleaseStringCritical(env, string, carray); 1974 CHECK_JNI_EXIT_VOID(); 1975 } 1976 1977 static jweak Check_NewWeakGlobalRef(JNIEnv* env, jobject obj) { 1978 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1979 return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj)); 1980 } 1981 1982 static void Check_DeleteWeakGlobalRef(JNIEnv* env, jweak obj) { 1983 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj); 1984 baseEnv(env)->DeleteWeakGlobalRef(env, obj); 1985 CHECK_JNI_EXIT_VOID(); 1986 } 1987 1988 static jboolean Check_ExceptionCheck(JNIEnv* env) { 1989 CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env); 1990 return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env)); 1991 } 1992 1993 static jobjectRefType Check_GetObjectRefType(JNIEnv* env, jobject obj) { 1994 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1995 // TODO: proper decoding of jobjectRefType! 1996 return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj)); 1997 } 1998 1999 static jobject Check_NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) { 2000 CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity); 2001 return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity)); 2002 } 2003 2004 static void* Check_GetDirectBufferAddress(JNIEnv* env, jobject buf) { 2005 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf); 2006 // TODO: check that 'buf' is a java.nio.Buffer. 2007 return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf)); 2008 } 2009 2010 static jlong Check_GetDirectBufferCapacity(JNIEnv* env, jobject buf) { 2011 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf); 2012 // TODO: check that 'buf' is a java.nio.Buffer. 2013 return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf)); 2014 } 2015 2016 2017 /* 2018 * =========================================================================== 2019 * JNI invocation functions 2020 * =========================================================================== 2021 */ 2022 2023 static jint Check_DestroyJavaVM(JavaVM* vm) { 2024 ScopedCheck sc(false, __FUNCTION__); 2025 sc.check(true, "v", vm); 2026 return CHECK_JNI_EXIT("I", baseVm(vm)->DestroyJavaVM(vm)); 2027 } 2028 2029 static jint Check_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) { 2030 ScopedCheck sc(false, __FUNCTION__); 2031 sc.check(true, "vpt", vm, p_env, thr_args); 2032 return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThread(vm, p_env, thr_args)); 2033 } 2034 2035 static jint Check_AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) { 2036 ScopedCheck sc(false, __FUNCTION__); 2037 sc.check(true, "vpt", vm, p_env, thr_args); 2038 return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args)); 2039 } 2040 2041 static jint Check_DetachCurrentThread(JavaVM* vm) { 2042 ScopedCheck sc(true, __FUNCTION__); 2043 sc.check(true, "v", vm); 2044 return CHECK_JNI_EXIT("I", baseVm(vm)->DetachCurrentThread(vm)); 2045 } 2046 2047 static jint Check_GetEnv(JavaVM* vm, void** env, jint version) { 2048 ScopedCheck sc(true, __FUNCTION__); 2049 sc.check(true, "v", vm); 2050 return CHECK_JNI_EXIT("I", baseVm(vm)->GetEnv(vm, env, version)); 2051 } 2052 2053 2054 /* 2055 * =========================================================================== 2056 * Function tables 2057 * =========================================================================== 2058 */ 2059 2060 static const struct JNINativeInterface gCheckNativeInterface = { 2061 NULL, 2062 NULL, 2063 NULL, 2064 NULL, 2065 2066 Check_GetVersion, 2067 2068 Check_DefineClass, 2069 Check_FindClass, 2070 2071 Check_FromReflectedMethod, 2072 Check_FromReflectedField, 2073 Check_ToReflectedMethod, 2074 2075 Check_GetSuperclass, 2076 Check_IsAssignableFrom, 2077 2078 Check_ToReflectedField, 2079 2080 Check_Throw, 2081 Check_ThrowNew, 2082 Check_ExceptionOccurred, 2083 Check_ExceptionDescribe, 2084 Check_ExceptionClear, 2085 Check_FatalError, 2086 2087 Check_PushLocalFrame, 2088 Check_PopLocalFrame, 2089 2090 Check_NewGlobalRef, 2091 Check_DeleteGlobalRef, 2092 Check_DeleteLocalRef, 2093 Check_IsSameObject, 2094 Check_NewLocalRef, 2095 Check_EnsureLocalCapacity, 2096 2097 Check_AllocObject, 2098 Check_NewObject, 2099 Check_NewObjectV, 2100 Check_NewObjectA, 2101 2102 Check_GetObjectClass, 2103 Check_IsInstanceOf, 2104 2105 Check_GetMethodID, 2106 2107 Check_CallObjectMethod, 2108 Check_CallObjectMethodV, 2109 Check_CallObjectMethodA, 2110 Check_CallBooleanMethod, 2111 Check_CallBooleanMethodV, 2112 Check_CallBooleanMethodA, 2113 Check_CallByteMethod, 2114 Check_CallByteMethodV, 2115 Check_CallByteMethodA, 2116 Check_CallCharMethod, 2117 Check_CallCharMethodV, 2118 Check_CallCharMethodA, 2119 Check_CallShortMethod, 2120 Check_CallShortMethodV, 2121 Check_CallShortMethodA, 2122 Check_CallIntMethod, 2123 Check_CallIntMethodV, 2124 Check_CallIntMethodA, 2125 Check_CallLongMethod, 2126 Check_CallLongMethodV, 2127 Check_CallLongMethodA, 2128 Check_CallFloatMethod, 2129 Check_CallFloatMethodV, 2130 Check_CallFloatMethodA, 2131 Check_CallDoubleMethod, 2132 Check_CallDoubleMethodV, 2133 Check_CallDoubleMethodA, 2134 Check_CallVoidMethod, 2135 Check_CallVoidMethodV, 2136 Check_CallVoidMethodA, 2137 2138 Check_CallNonvirtualObjectMethod, 2139 Check_CallNonvirtualObjectMethodV, 2140 Check_CallNonvirtualObjectMethodA, 2141 Check_CallNonvirtualBooleanMethod, 2142 Check_CallNonvirtualBooleanMethodV, 2143 Check_CallNonvirtualBooleanMethodA, 2144 Check_CallNonvirtualByteMethod, 2145 Check_CallNonvirtualByteMethodV, 2146 Check_CallNonvirtualByteMethodA, 2147 Check_CallNonvirtualCharMethod, 2148 Check_CallNonvirtualCharMethodV, 2149 Check_CallNonvirtualCharMethodA, 2150 Check_CallNonvirtualShortMethod, 2151 Check_CallNonvirtualShortMethodV, 2152 Check_CallNonvirtualShortMethodA, 2153 Check_CallNonvirtualIntMethod, 2154 Check_CallNonvirtualIntMethodV, 2155 Check_CallNonvirtualIntMethodA, 2156 Check_CallNonvirtualLongMethod, 2157 Check_CallNonvirtualLongMethodV, 2158 Check_CallNonvirtualLongMethodA, 2159 Check_CallNonvirtualFloatMethod, 2160 Check_CallNonvirtualFloatMethodV, 2161 Check_CallNonvirtualFloatMethodA, 2162 Check_CallNonvirtualDoubleMethod, 2163 Check_CallNonvirtualDoubleMethodV, 2164 Check_CallNonvirtualDoubleMethodA, 2165 Check_CallNonvirtualVoidMethod, 2166 Check_CallNonvirtualVoidMethodV, 2167 Check_CallNonvirtualVoidMethodA, 2168 2169 Check_GetFieldID, 2170 2171 Check_GetObjectField, 2172 Check_GetBooleanField, 2173 Check_GetByteField, 2174 Check_GetCharField, 2175 Check_GetShortField, 2176 Check_GetIntField, 2177 Check_GetLongField, 2178 Check_GetFloatField, 2179 Check_GetDoubleField, 2180 Check_SetObjectField, 2181 Check_SetBooleanField, 2182 Check_SetByteField, 2183 Check_SetCharField, 2184 Check_SetShortField, 2185 Check_SetIntField, 2186 Check_SetLongField, 2187 Check_SetFloatField, 2188 Check_SetDoubleField, 2189 2190 Check_GetStaticMethodID, 2191 2192 Check_CallStaticObjectMethod, 2193 Check_CallStaticObjectMethodV, 2194 Check_CallStaticObjectMethodA, 2195 Check_CallStaticBooleanMethod, 2196 Check_CallStaticBooleanMethodV, 2197 Check_CallStaticBooleanMethodA, 2198 Check_CallStaticByteMethod, 2199 Check_CallStaticByteMethodV, 2200 Check_CallStaticByteMethodA, 2201 Check_CallStaticCharMethod, 2202 Check_CallStaticCharMethodV, 2203 Check_CallStaticCharMethodA, 2204 Check_CallStaticShortMethod, 2205 Check_CallStaticShortMethodV, 2206 Check_CallStaticShortMethodA, 2207 Check_CallStaticIntMethod, 2208 Check_CallStaticIntMethodV, 2209 Check_CallStaticIntMethodA, 2210 Check_CallStaticLongMethod, 2211 Check_CallStaticLongMethodV, 2212 Check_CallStaticLongMethodA, 2213 Check_CallStaticFloatMethod, 2214 Check_CallStaticFloatMethodV, 2215 Check_CallStaticFloatMethodA, 2216 Check_CallStaticDoubleMethod, 2217 Check_CallStaticDoubleMethodV, 2218 Check_CallStaticDoubleMethodA, 2219 Check_CallStaticVoidMethod, 2220 Check_CallStaticVoidMethodV, 2221 Check_CallStaticVoidMethodA, 2222 2223 Check_GetStaticFieldID, 2224 2225 Check_GetStaticObjectField, 2226 Check_GetStaticBooleanField, 2227 Check_GetStaticByteField, 2228 Check_GetStaticCharField, 2229 Check_GetStaticShortField, 2230 Check_GetStaticIntField, 2231 Check_GetStaticLongField, 2232 Check_GetStaticFloatField, 2233 Check_GetStaticDoubleField, 2234 2235 Check_SetStaticObjectField, 2236 Check_SetStaticBooleanField, 2237 Check_SetStaticByteField, 2238 Check_SetStaticCharField, 2239 Check_SetStaticShortField, 2240 Check_SetStaticIntField, 2241 Check_SetStaticLongField, 2242 Check_SetStaticFloatField, 2243 Check_SetStaticDoubleField, 2244 2245 Check_NewString, 2246 2247 Check_GetStringLength, 2248 Check_GetStringChars, 2249 Check_ReleaseStringChars, 2250 2251 Check_NewStringUTF, 2252 Check_GetStringUTFLength, 2253 Check_GetStringUTFChars, 2254 Check_ReleaseStringUTFChars, 2255 2256 Check_GetArrayLength, 2257 Check_NewObjectArray, 2258 Check_GetObjectArrayElement, 2259 Check_SetObjectArrayElement, 2260 2261 Check_NewBooleanArray, 2262 Check_NewByteArray, 2263 Check_NewCharArray, 2264 Check_NewShortArray, 2265 Check_NewIntArray, 2266 Check_NewLongArray, 2267 Check_NewFloatArray, 2268 Check_NewDoubleArray, 2269 2270 Check_GetBooleanArrayElements, 2271 Check_GetByteArrayElements, 2272 Check_GetCharArrayElements, 2273 Check_GetShortArrayElements, 2274 Check_GetIntArrayElements, 2275 Check_GetLongArrayElements, 2276 Check_GetFloatArrayElements, 2277 Check_GetDoubleArrayElements, 2278 2279 Check_ReleaseBooleanArrayElements, 2280 Check_ReleaseByteArrayElements, 2281 Check_ReleaseCharArrayElements, 2282 Check_ReleaseShortArrayElements, 2283 Check_ReleaseIntArrayElements, 2284 Check_ReleaseLongArrayElements, 2285 Check_ReleaseFloatArrayElements, 2286 Check_ReleaseDoubleArrayElements, 2287 2288 Check_GetBooleanArrayRegion, 2289 Check_GetByteArrayRegion, 2290 Check_GetCharArrayRegion, 2291 Check_GetShortArrayRegion, 2292 Check_GetIntArrayRegion, 2293 Check_GetLongArrayRegion, 2294 Check_GetFloatArrayRegion, 2295 Check_GetDoubleArrayRegion, 2296 Check_SetBooleanArrayRegion, 2297 Check_SetByteArrayRegion, 2298 Check_SetCharArrayRegion, 2299 Check_SetShortArrayRegion, 2300 Check_SetIntArrayRegion, 2301 Check_SetLongArrayRegion, 2302 Check_SetFloatArrayRegion, 2303 Check_SetDoubleArrayRegion, 2304 2305 Check_RegisterNatives, 2306 Check_UnregisterNatives, 2307 2308 Check_MonitorEnter, 2309 Check_MonitorExit, 2310 2311 Check_GetJavaVM, 2312 2313 Check_GetStringRegion, 2314 Check_GetStringUTFRegion, 2315 2316 Check_GetPrimitiveArrayCritical, 2317 Check_ReleasePrimitiveArrayCritical, 2318 2319 Check_GetStringCritical, 2320 Check_ReleaseStringCritical, 2321 2322 Check_NewWeakGlobalRef, 2323 Check_DeleteWeakGlobalRef, 2324 2325 Check_ExceptionCheck, 2326 2327 Check_NewDirectByteBuffer, 2328 Check_GetDirectBufferAddress, 2329 Check_GetDirectBufferCapacity, 2330 2331 Check_GetObjectRefType 2332 }; 2333 2334 static const struct JNIInvokeInterface gCheckInvokeInterface = { 2335 NULL, 2336 NULL, 2337 NULL, 2338 2339 Check_DestroyJavaVM, 2340 Check_AttachCurrentThread, 2341 Check_DetachCurrentThread, 2342 2343 Check_GetEnv, 2344 2345 Check_AttachCurrentThreadAsDaemon, 2346 }; 2347 2348 /* 2349 * Replace the normal table with the checked table. 2350 */ 2351 void dvmUseCheckedJniEnv(JNIEnvExt* pEnv) { 2352 assert(pEnv->funcTable != &gCheckNativeInterface); 2353 pEnv->baseFuncTable = pEnv->funcTable; 2354 pEnv->funcTable = &gCheckNativeInterface; 2355 } 2356 2357 /* 2358 * Replace the normal table with the checked table. 2359 */ 2360 void dvmUseCheckedJniVm(JavaVMExt* pVm) { 2361 assert(pVm->funcTable != &gCheckInvokeInterface); 2362 pVm->baseFuncTable = pVm->funcTable; 2363 pVm->funcTable = &gCheckInvokeInterface; 2364 } 2365