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"); 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"); 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 on invalid %s reference (%p)", 302 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: set field '%s' expected type %s, got %s", 313 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: accessing non-static field %s as static", field->name); 324 } else { 325 ALOGW("JNI WARNING: accessing static field %s as non-static", 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: field operation on invalid reference (%p)", 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 fieldID %p not valid for class %s", 365 fieldID, obj->clazz->descriptor); 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: expected return type '%s'", expectedType); 390 printWarn = true; 391 } else if (isStatic && !dvmIsStaticMethod(method)) { 392 if (isStatic) { 393 ALOGW("JNI WARNING: calling non-static method with static call"); 394 } else { 395 ALOGW("JNI WARNING: calling static method with non-static call"); 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", 421 fieldID, clazz->descriptor); 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", 445 method->clazz->descriptor, method->name, clazz->descriptor); 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", 466 method->clazz->descriptor, method->name, obj->clazz->descriptor); 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: received null array"); 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: jarray is an invalid %s reference (%p)", 752 indirectRefKindName(jarr), jarr); 753 printWarn = true; 754 } else if (obj->clazz->descriptor[0] != '[') { 755 ALOGW("JNI WARNING: jarray arg has wrong type (expected array, got %s)", 756 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", jobj); 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", jobj); 798 printWarn = true; 799 } else if (obj != NULL && !dvmIsHeapAddress(obj)) { 800 // TODO: when we remove workAroundAppJniBugs, this should be impossible. 801 ALOGW("JNI WARNING: native code passing in reference to invalid object %p %p", 802 jobj, obj); 803 printWarn = true; 804 } 805 } 806 807 if (printWarn) { 808 showLocation(); 809 abortMaybe(); 810 } 811 } 812 813 /* 814 * Verify that the "mode" argument passed to a primitive array Release 815 * function is one of the valid values. 816 */ 817 void checkReleaseMode(jint mode) { 818 if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) { 819 ALOGW("JNI WARNING: bad value for mode (%d) (%s)", mode, mFunctionName); 820 abortMaybe(); 821 } 822 } 823 824 void checkString(jstring s) { 825 checkInstance(s, gDvm.classJavaLangString, "jstring"); 826 } 827 828 void checkThreadArgs(void* thread_args) { 829 JavaVMAttachArgs* args = static_cast<JavaVMAttachArgs*>(thread_args); 830 if (args != NULL && args->version < JNI_VERSION_1_2) { 831 ALOGW("JNI WARNING: bad value for JNI version (%d) (%s)", args->version, mFunctionName); 832 abortMaybe(); 833 } 834 } 835 836 void checkThread(int flags) { 837 // Get the *correct* JNIEnv by going through our TLS pointer. 838 JNIEnvExt* threadEnv = dvmGetJNIEnvForThread(); 839 840 /* 841 * Verify that the current thread is (a) attached and (b) associated with 842 * this particular instance of JNIEnv. 843 */ 844 bool printWarn = false; 845 if (threadEnv == NULL) { 846 ALOGE("JNI ERROR: non-VM thread making JNI calls"); 847 // don't set printWarn -- it'll try to call showLocation() 848 dvmAbort(); 849 } else if ((JNIEnvExt*) mEnv != threadEnv) { 850 if (dvmThreadSelf()->threadId != threadEnv->envThreadId) { 851 ALOGE("JNI: threadEnv != thread->env?"); 852 dvmAbort(); 853 } 854 855 ALOGW("JNI WARNING: threadid=%d using env from threadid=%d", 856 threadEnv->envThreadId, ((JNIEnvExt*) mEnv)->envThreadId); 857 printWarn = true; 858 859 // If we're keeping broken code limping along, we need to suppress the abort... 860 if (gDvmJni.workAroundAppJniBugs) { 861 printWarn = false; 862 } 863 864 /* this is a bad idea -- need to throw as we exit, or abort func */ 865 //dvmThrowRuntimeException("invalid use of JNI env ptr"); 866 } else if (((JNIEnvExt*) mEnv)->self != dvmThreadSelf()) { 867 /* correct JNIEnv*; make sure the "self" pointer is correct */ 868 ALOGE("JNI ERROR: env->self != thread-self (%p vs. %p)", 869 ((JNIEnvExt*) mEnv)->self, dvmThreadSelf()); 870 dvmAbort(); 871 } 872 873 /* 874 * Verify that, if this thread previously made a critical "get" call, we 875 * do the corresponding "release" call before we try anything else. 876 */ 877 switch (flags & kFlag_CritMask) { 878 case kFlag_CritOkay: // okay to call this method 879 break; 880 case kFlag_CritBad: // not okay to call 881 if (threadEnv->critical) { 882 ALOGW("JNI WARNING: threadid=%d using JNI after critical get", 883 threadEnv->envThreadId); 884 printWarn = true; 885 } 886 break; 887 case kFlag_CritGet: // this is a "get" call 888 /* don't check here; we allow nested gets */ 889 threadEnv->critical++; 890 break; 891 case kFlag_CritRelease: // this is a "release" call 892 threadEnv->critical--; 893 if (threadEnv->critical < 0) { 894 ALOGW("JNI WARNING: threadid=%d called too many crit releases", 895 threadEnv->envThreadId); 896 printWarn = true; 897 } 898 break; 899 default: 900 assert(false); 901 } 902 903 /* 904 * Verify that, if an exception has been raised, the native code doesn't 905 * make any JNI calls other than the Exception* methods. 906 */ 907 bool printException = false; 908 if ((flags & kFlag_ExcepOkay) == 0 && dvmCheckException(dvmThreadSelf())) { 909 ALOGW("JNI WARNING: JNI method called with exception pending"); 910 printWarn = true; 911 printException = true; 912 } 913 914 if (printWarn) { 915 showLocation(); 916 } 917 if (printException) { 918 ALOGW("Pending exception is:"); 919 dvmLogExceptionStackTrace(); 920 } 921 if (printWarn) { 922 abortMaybe(); 923 } 924 } 925 926 /* 927 * Verify that "bytes" points to valid "modified UTF-8" data. 928 */ 929 void checkUtfString(const char* bytes, bool nullable) { 930 if (bytes == NULL) { 931 if (!nullable) { 932 ALOGW("JNI WARNING: non-nullable const char* was NULL"); 933 showLocation(); 934 abortMaybe(); 935 } 936 return; 937 } 938 939 const char* errorKind = NULL; 940 u1 utf8 = checkUtfBytes(bytes, &errorKind); 941 if (errorKind != NULL) { 942 ALOGW("JNI WARNING: input is not valid Modified UTF-8: illegal %s byte %#x", errorKind, utf8); 943 ALOGW(" string: '%s'", bytes); 944 showLocation(); 945 abortMaybe(); 946 } 947 } 948 949 /* 950 * Verify that "jobj" is a valid non-NULL object reference, and points to 951 * an instance of expectedClass. 952 * 953 * Because we're looking at an object on the GC heap, we have to switch 954 * to "running" mode before doing the checks. 955 */ 956 void checkInstance(jobject jobj, ClassObject* expectedClass, const char* argName) { 957 if (jobj == NULL) { 958 ALOGW("JNI WARNING: received null %s", argName); 959 showLocation(); 960 abortMaybe(); 961 return; 962 } 963 964 ScopedCheckJniThreadState ts(mEnv); 965 bool printWarn = false; 966 967 Object* obj = dvmDecodeIndirectRef(self(), jobj); 968 if (!dvmIsHeapAddress(obj)) { 969 ALOGW("JNI WARNING: %s is an invalid %s reference (%p)", 970 argName, indirectRefKindName(jobj), jobj); 971 printWarn = true; 972 } else if (obj->clazz != expectedClass) { 973 ALOGW("JNI WARNING: %s arg has wrong type (expected %s, got %s)", 974 argName, expectedClass->descriptor, obj->clazz->descriptor); 975 printWarn = true; 976 } 977 978 if (printWarn) { 979 showLocation(); 980 abortMaybe(); 981 } 982 } 983 984 static u1 checkUtfBytes(const char* bytes, const char** errorKind) { 985 while (*bytes != '\0') { 986 u1 utf8 = *(bytes++); 987 // Switch on the high four bits. 988 switch (utf8 >> 4) { 989 case 0x00: 990 case 0x01: 991 case 0x02: 992 case 0x03: 993 case 0x04: 994 case 0x05: 995 case 0x06: 996 case 0x07: 997 // Bit pattern 0xxx. No need for any extra bytes. 998 break; 999 case 0x08: 1000 case 0x09: 1001 case 0x0a: 1002 case 0x0b: 1003 case 0x0f: 1004 /* 1005 * Bit pattern 10xx or 1111, which are illegal start bytes. 1006 * Note: 1111 is valid for normal UTF-8, but not the 1007 * modified UTF-8 used here. 1008 */ 1009 *errorKind = "start"; 1010 return utf8; 1011 case 0x0e: 1012 // Bit pattern 1110, so there are two additional bytes. 1013 utf8 = *(bytes++); 1014 if ((utf8 & 0xc0) != 0x80) { 1015 *errorKind = "continuation"; 1016 return utf8; 1017 } 1018 // Fall through to take care of the final byte. 1019 case 0x0c: 1020 case 0x0d: 1021 // Bit pattern 110x, so there is one additional byte. 1022 utf8 = *(bytes++); 1023 if ((utf8 & 0xc0) != 0x80) { 1024 *errorKind = "continuation"; 1025 return utf8; 1026 } 1027 break; 1028 } 1029 } 1030 return 0; 1031 } 1032 1033 /** 1034 * Returns a human-readable name for the given primitive type. 1035 */ 1036 static const char* primitiveTypeToName(PrimitiveType primType) { 1037 switch (primType) { 1038 case PRIM_VOID: return "void"; 1039 case PRIM_BOOLEAN: return "boolean"; 1040 case PRIM_BYTE: return "byte"; 1041 case PRIM_SHORT: return "short"; 1042 case PRIM_CHAR: return "char"; 1043 case PRIM_INT: return "int"; 1044 case PRIM_LONG: return "long"; 1045 case PRIM_FLOAT: return "float"; 1046 case PRIM_DOUBLE: return "double"; 1047 case PRIM_NOT: return "Object/array"; 1048 default: return "???"; 1049 } 1050 } 1051 1052 void showLocation() { 1053 const Method* method = dvmGetCurrentJNIMethod(); 1054 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 1055 ALOGW(" in %s.%s:%s (%s)", method->clazz->descriptor, method->name, desc, mFunctionName); 1056 free(desc); 1057 } 1058 1059 // Disallow copy and assignment. 1060 ScopedCheck(const ScopedCheck&); 1061 void operator=(const ScopedCheck&); 1062 }; 1063 1064 /* 1065 * =========================================================================== 1066 * Guarded arrays 1067 * =========================================================================== 1068 */ 1069 1070 #define kGuardLen 512 /* must be multiple of 2 */ 1071 #define kGuardPattern 0xd5e3 /* uncommon values; d5e3d5e3 invalid addr */ 1072 #define kGuardMagic 0xffd5aa96 1073 1074 /* this gets tucked in at the start of the buffer; struct size must be even */ 1075 struct GuardedCopy { 1076 u4 magic; 1077 uLong adler; 1078 size_t originalLen; 1079 const void* originalPtr; 1080 1081 /* find the GuardedCopy given the pointer into the "live" data */ 1082 static inline const GuardedCopy* fromData(const void* dataBuf) { 1083 return reinterpret_cast<const GuardedCopy*>(actualBuffer(dataBuf)); 1084 } 1085 1086 /* 1087 * Create an over-sized buffer to hold the contents of "buf". Copy it in, 1088 * filling in the area around it with guard data. 1089 * 1090 * We use a 16-bit pattern to make a rogue memset less likely to elude us. 1091 */ 1092 static void* create(const void* buf, size_t len, bool modOkay) { 1093 size_t newLen = actualLength(len); 1094 u1* newBuf = debugAlloc(newLen); 1095 1096 /* fill it in with a pattern */ 1097 u2* pat = (u2*) newBuf; 1098 for (size_t i = 0; i < newLen / 2; i++) { 1099 *pat++ = kGuardPattern; 1100 } 1101 1102 /* copy the data in; note "len" could be zero */ 1103 memcpy(newBuf + kGuardLen / 2, buf, len); 1104 1105 /* if modification is not expected, grab a checksum */ 1106 uLong adler = 0; 1107 if (!modOkay) { 1108 adler = adler32(0L, Z_NULL, 0); 1109 adler = adler32(adler, (const Bytef*)buf, len); 1110 *(uLong*)newBuf = adler; 1111 } 1112 1113 GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf); 1114 pExtra->magic = kGuardMagic; 1115 pExtra->adler = adler; 1116 pExtra->originalPtr = buf; 1117 pExtra->originalLen = len; 1118 1119 return newBuf + kGuardLen / 2; 1120 } 1121 1122 /* 1123 * Free up the guard buffer, scrub it, and return the original pointer. 1124 */ 1125 static void* destroy(void* dataBuf) { 1126 const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf); 1127 void* originalPtr = (void*) pExtra->originalPtr; 1128 size_t len = pExtra->originalLen; 1129 debugFree(dataBuf, len); 1130 return originalPtr; 1131 } 1132 1133 /* 1134 * Verify the guard area and, if "modOkay" is false, that the data itself 1135 * has not been altered. 1136 * 1137 * The caller has already checked that "dataBuf" is non-NULL. 1138 */ 1139 static bool check(const void* dataBuf, bool modOkay) { 1140 static const u4 kMagicCmp = kGuardMagic; 1141 const u1* fullBuf = actualBuffer(dataBuf); 1142 const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf); 1143 1144 /* 1145 * Before we do anything with "pExtra", check the magic number. We 1146 * do the check with memcmp rather than "==" in case the pointer is 1147 * unaligned. If it points to completely bogus memory we're going 1148 * to crash, but there's no easy way around that. 1149 */ 1150 if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) { 1151 u1 buf[4]; 1152 memcpy(buf, &pExtra->magic, 4); 1153 ALOGE("JNI: guard magic does not match (found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?", 1154 buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */ 1155 return false; 1156 } 1157 1158 size_t len = pExtra->originalLen; 1159 1160 /* check bottom half of guard; skip over optional checksum storage */ 1161 const u2* pat = (u2*) fullBuf; 1162 for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) { 1163 if (pat[i] != kGuardPattern) { 1164 ALOGE("JNI: guard pattern(1) disturbed at %p + %d", fullBuf, i*2); 1165 return false; 1166 } 1167 } 1168 1169 int offset = kGuardLen / 2 + len; 1170 if (offset & 0x01) { 1171 /* odd byte; expected value depends on endian-ness of host */ 1172 const u2 patSample = kGuardPattern; 1173 if (fullBuf[offset] != ((const u1*) &patSample)[1]) { 1174 ALOGE("JNI: guard pattern disturbed in odd byte after %p (+%d) 0x%02x 0x%02x", 1175 fullBuf, offset, fullBuf[offset], ((const u1*) &patSample)[1]); 1176 return false; 1177 } 1178 offset++; 1179 } 1180 1181 /* check top half of guard */ 1182 pat = (u2*) (fullBuf + offset); 1183 for (size_t i = 0; i < kGuardLen / 4; i++) { 1184 if (pat[i] != kGuardPattern) { 1185 ALOGE("JNI: guard pattern(2) disturbed at %p + %d", fullBuf, offset + i*2); 1186 return false; 1187 } 1188 } 1189 1190 /* 1191 * If modification is not expected, verify checksum. Strictly speaking 1192 * this is wrong: if we told the client that we made a copy, there's no 1193 * reason they can't alter the buffer. 1194 */ 1195 if (!modOkay) { 1196 uLong adler = adler32(0L, Z_NULL, 0); 1197 adler = adler32(adler, (const Bytef*)dataBuf, len); 1198 if (pExtra->adler != adler) { 1199 ALOGE("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p", 1200 pExtra->adler, adler, dataBuf); 1201 return false; 1202 } 1203 } 1204 1205 return true; 1206 } 1207 1208 private: 1209 static u1* debugAlloc(size_t len) { 1210 void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); 1211 if (result == MAP_FAILED) { 1212 ALOGE("GuardedCopy::create mmap(%d) failed: %s", len, strerror(errno)); 1213 dvmAbort(); 1214 } 1215 return reinterpret_cast<u1*>(result); 1216 } 1217 1218 static void debugFree(void* dataBuf, size_t len) { 1219 u1* fullBuf = actualBuffer(dataBuf); 1220 size_t totalByteCount = actualLength(len); 1221 // TODO: we could mprotect instead, and keep the allocation around for a while. 1222 // This would be even more expensive, but it might catch more errors. 1223 // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) { 1224 // ALOGW("mprotect(PROT_NONE) failed: %s", strerror(errno)); 1225 // } 1226 if (munmap(fullBuf, totalByteCount) != 0) { 1227 ALOGW("munmap failed: %s", strerror(errno)); 1228 dvmAbort(); 1229 } 1230 } 1231 1232 static const u1* actualBuffer(const void* dataBuf) { 1233 return reinterpret_cast<const u1*>(dataBuf) - kGuardLen / 2; 1234 } 1235 1236 static u1* actualBuffer(void* dataBuf) { 1237 return reinterpret_cast<u1*>(dataBuf) - kGuardLen / 2; 1238 } 1239 1240 // Underlying length of a user allocation of 'length' bytes. 1241 static size_t actualLength(size_t length) { 1242 return (length + kGuardLen + 1) & ~0x01; 1243 } 1244 }; 1245 1246 /* 1247 * Return the width, in bytes, of a primitive type. 1248 */ 1249 static int dvmPrimitiveTypeWidth(PrimitiveType primType) { 1250 switch (primType) { 1251 case PRIM_BOOLEAN: return 1; 1252 case PRIM_BYTE: return 1; 1253 case PRIM_SHORT: return 2; 1254 case PRIM_CHAR: return 2; 1255 case PRIM_INT: return 4; 1256 case PRIM_LONG: return 8; 1257 case PRIM_FLOAT: return 4; 1258 case PRIM_DOUBLE: return 8; 1259 case PRIM_VOID: 1260 default: { 1261 assert(false); 1262 return -1; 1263 } 1264 } 1265 } 1266 1267 /* 1268 * Create a guarded copy of a primitive array. Modifications to the copied 1269 * data are allowed. Returns a pointer to the copied data. 1270 */ 1271 static void* createGuardedPACopy(JNIEnv* env, const jarray jarr, jboolean* isCopy) { 1272 ScopedCheckJniThreadState ts(env); 1273 1274 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(dvmThreadSelf(), jarr); 1275 PrimitiveType primType = arrObj->clazz->elementClass->primitiveType; 1276 int len = arrObj->length * dvmPrimitiveTypeWidth(primType); 1277 void* result = GuardedCopy::create(arrObj->contents, len, true); 1278 if (isCopy != NULL) { 1279 *isCopy = JNI_TRUE; 1280 } 1281 return result; 1282 } 1283 1284 /* 1285 * Perform the array "release" operation, which may or may not copy data 1286 * back into the VM, and may or may not release the underlying storage. 1287 */ 1288 static void* releaseGuardedPACopy(JNIEnv* env, jarray jarr, void* dataBuf, int mode) { 1289 ScopedCheckJniThreadState ts(env); 1290 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(dvmThreadSelf(), jarr); 1291 1292 if (!GuardedCopy::check(dataBuf, true)) { 1293 ALOGE("JNI: failed guarded copy check in releaseGuardedPACopy"); 1294 abortMaybe(); 1295 return NULL; 1296 } 1297 1298 if (mode != JNI_ABORT) { 1299 size_t len = GuardedCopy::fromData(dataBuf)->originalLen; 1300 memcpy(arrObj->contents, dataBuf, len); 1301 } 1302 1303 u1* result = NULL; 1304 if (mode != JNI_COMMIT) { 1305 result = (u1*) GuardedCopy::destroy(dataBuf); 1306 } else { 1307 result = (u1*) (void*) GuardedCopy::fromData(dataBuf)->originalPtr; 1308 } 1309 1310 /* pointer is to the array contents; back up to the array object */ 1311 result -= OFFSETOF_MEMBER(ArrayObject, contents); 1312 return result; 1313 } 1314 1315 1316 /* 1317 * =========================================================================== 1318 * JNI functions 1319 * =========================================================================== 1320 */ 1321 1322 #define CHECK_JNI_ENTRY(flags, types, args...) \ 1323 ScopedCheck sc(env, flags, __FUNCTION__); \ 1324 sc.check(true, types, ##args) 1325 1326 #define CHECK_JNI_EXIT(type, exp) ({ \ 1327 typeof (exp) _rc = (exp); \ 1328 sc.check(false, type, _rc); \ 1329 _rc; }) 1330 #define CHECK_JNI_EXIT_VOID() \ 1331 sc.check(false, "V") 1332 1333 static jint Check_GetVersion(JNIEnv* env) { 1334 CHECK_JNI_ENTRY(kFlag_Default, "E", env); 1335 return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env)); 1336 } 1337 1338 static jclass Check_DefineClass(JNIEnv* env, const char* name, jobject loader, 1339 const jbyte* buf, jsize bufLen) 1340 { 1341 CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen); 1342 sc.checkClassName(name); 1343 return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen)); 1344 } 1345 1346 static jclass Check_FindClass(JNIEnv* env, const char* name) { 1347 CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name); 1348 sc.checkClassName(name); 1349 return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name)); 1350 } 1351 1352 static jclass Check_GetSuperclass(JNIEnv* env, jclass clazz) { 1353 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz); 1354 return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, clazz)); 1355 } 1356 1357 static jboolean Check_IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2) { 1358 CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, clazz1, clazz2); 1359 return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, clazz1, clazz2)); 1360 } 1361 1362 static jmethodID Check_FromReflectedMethod(JNIEnv* env, jobject method) { 1363 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method); 1364 // TODO: check that 'field' is a java.lang.reflect.Method. 1365 return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method)); 1366 } 1367 1368 static jfieldID Check_FromReflectedField(JNIEnv* env, jobject field) { 1369 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field); 1370 // TODO: check that 'field' is a java.lang.reflect.Field. 1371 return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field)); 1372 } 1373 1374 static jobject Check_ToReflectedMethod(JNIEnv* env, jclass cls, 1375 jmethodID methodID, jboolean isStatic) 1376 { 1377 CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, methodID, isStatic); 1378 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, methodID, isStatic)); 1379 } 1380 1381 static jobject Check_ToReflectedField(JNIEnv* env, jclass cls, 1382 jfieldID fieldID, jboolean isStatic) 1383 { 1384 CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fieldID, isStatic); 1385 return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fieldID, isStatic)); 1386 } 1387 1388 static jint Check_Throw(JNIEnv* env, jthrowable obj) { 1389 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1390 // TODO: check that 'obj' is a java.lang.Throwable. 1391 return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj)); 1392 } 1393 1394 static jint Check_ThrowNew(JNIEnv* env, jclass clazz, const char* message) { 1395 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, clazz, message); 1396 return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, clazz, message)); 1397 } 1398 1399 static jthrowable Check_ExceptionOccurred(JNIEnv* env) { 1400 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env); 1401 return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env)); 1402 } 1403 1404 static void Check_ExceptionDescribe(JNIEnv* env) { 1405 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env); 1406 baseEnv(env)->ExceptionDescribe(env); 1407 CHECK_JNI_EXIT_VOID(); 1408 } 1409 1410 static void Check_ExceptionClear(JNIEnv* env) { 1411 CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env); 1412 baseEnv(env)->ExceptionClear(env); 1413 CHECK_JNI_EXIT_VOID(); 1414 } 1415 1416 static void Check_FatalError(JNIEnv* env, const char* msg) { 1417 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg); 1418 baseEnv(env)->FatalError(env, msg); 1419 CHECK_JNI_EXIT_VOID(); 1420 } 1421 1422 static jint Check_PushLocalFrame(JNIEnv* env, jint capacity) { 1423 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity); 1424 return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity)); 1425 } 1426 1427 static jobject Check_PopLocalFrame(JNIEnv* env, jobject res) { 1428 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res); 1429 return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res)); 1430 } 1431 1432 static jobject Check_NewGlobalRef(JNIEnv* env, jobject obj) { 1433 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1434 return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj)); 1435 } 1436 1437 static void Check_DeleteGlobalRef(JNIEnv* env, jobject globalRef) { 1438 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef); 1439 if (globalRef != NULL && dvmGetJNIRefType(sc.self(), globalRef) != JNIGlobalRefType) { 1440 ALOGW("JNI WARNING: DeleteGlobalRef on non-global %p (type=%d)", 1441 globalRef, dvmGetJNIRefType(sc.self(), globalRef)); 1442 abortMaybe(); 1443 } else { 1444 baseEnv(env)->DeleteGlobalRef(env, globalRef); 1445 CHECK_JNI_EXIT_VOID(); 1446 } 1447 } 1448 1449 static jobject Check_NewLocalRef(JNIEnv* env, jobject ref) { 1450 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref); 1451 return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref)); 1452 } 1453 1454 static void Check_DeleteLocalRef(JNIEnv* env, jobject localRef) { 1455 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef); 1456 if (localRef != NULL && dvmGetJNIRefType(sc.self(), localRef) != JNILocalRefType) { 1457 ALOGW("JNI WARNING: DeleteLocalRef on non-local %p (type=%d)", 1458 localRef, dvmGetJNIRefType(sc.self(), localRef)); 1459 abortMaybe(); 1460 } else { 1461 baseEnv(env)->DeleteLocalRef(env, localRef); 1462 CHECK_JNI_EXIT_VOID(); 1463 } 1464 } 1465 1466 static jint Check_EnsureLocalCapacity(JNIEnv *env, jint capacity) { 1467 CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity); 1468 return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity)); 1469 } 1470 1471 static jboolean Check_IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) { 1472 CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2); 1473 return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2)); 1474 } 1475 1476 static jobject Check_AllocObject(JNIEnv* env, jclass clazz) { 1477 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz); 1478 return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, clazz)); 1479 } 1480 1481 static jobject Check_NewObject(JNIEnv* env, jclass clazz, jmethodID methodID, ...) { 1482 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); 1483 va_list args; 1484 va_start(args, methodID); 1485 jobject result = baseEnv(env)->NewObjectV(env, clazz, methodID, args); 1486 va_end(args); 1487 return CHECK_JNI_EXIT("L", result); 1488 } 1489 1490 static jobject Check_NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID, va_list args) { 1491 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); 1492 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, clazz, methodID, args)); 1493 } 1494 1495 static jobject Check_NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID, jvalue* args) { 1496 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); 1497 return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, clazz, methodID, args)); 1498 } 1499 1500 static jclass Check_GetObjectClass(JNIEnv* env, jobject obj) { 1501 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1502 return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj)); 1503 } 1504 1505 static jboolean Check_IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) { 1506 CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, clazz); 1507 return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, clazz)); 1508 } 1509 1510 static jmethodID Check_GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) { 1511 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1512 return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, clazz, name, sig)); 1513 } 1514 1515 static jfieldID Check_GetFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) { 1516 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1517 return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, clazz, name, sig)); 1518 } 1519 1520 static jmethodID Check_GetStaticMethodID(JNIEnv* env, jclass clazz, 1521 const char* name, const char* sig) 1522 { 1523 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1524 return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, clazz, name, sig)); 1525 } 1526 1527 static jfieldID Check_GetStaticFieldID(JNIEnv* env, jclass clazz, 1528 const char* name, const char* sig) 1529 { 1530 CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig); 1531 return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, clazz, name, sig)); 1532 } 1533 1534 #define FIELD_ACCESSORS(_ctype, _jname, _ftype, _type) \ 1535 static _ctype Check_GetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fieldID) { \ 1536 CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, clazz, fieldID); \ 1537 sc.checkStaticFieldID(clazz, fieldID); \ 1538 sc.checkFieldTypeForGet(fieldID, _type, true); \ 1539 return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, clazz, fieldID)); \ 1540 } \ 1541 static _ctype Check_Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fieldID) { \ 1542 CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fieldID); \ 1543 sc.checkInstanceFieldID(obj, fieldID); \ 1544 sc.checkFieldTypeForGet(fieldID, _type, false); \ 1545 return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fieldID)); \ 1546 } \ 1547 static void Check_SetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fieldID, _ctype value) { \ 1548 CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, clazz, fieldID, value); \ 1549 sc.checkStaticFieldID(clazz, fieldID); \ 1550 /* "value" arg only used when type == ref */ \ 1551 sc.checkFieldTypeForSet((jobject)(u4)value, fieldID, _ftype, true); \ 1552 baseEnv(env)->SetStatic##_jname##Field(env, clazz, fieldID, value); \ 1553 CHECK_JNI_EXIT_VOID(); \ 1554 } \ 1555 static void Check_Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fieldID, _ctype value) { \ 1556 CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fieldID, value); \ 1557 sc.checkInstanceFieldID(obj, fieldID); \ 1558 /* "value" arg only used when type == ref */ \ 1559 sc.checkFieldTypeForSet((jobject)(u4) value, fieldID, _ftype, false); \ 1560 baseEnv(env)->Set##_jname##Field(env, obj, fieldID, value); \ 1561 CHECK_JNI_EXIT_VOID(); \ 1562 } 1563 1564 FIELD_ACCESSORS(jobject, Object, PRIM_NOT, "L"); 1565 FIELD_ACCESSORS(jboolean, Boolean, PRIM_BOOLEAN, "Z"); 1566 FIELD_ACCESSORS(jbyte, Byte, PRIM_BYTE, "B"); 1567 FIELD_ACCESSORS(jchar, Char, PRIM_CHAR, "C"); 1568 FIELD_ACCESSORS(jshort, Short, PRIM_SHORT, "S"); 1569 FIELD_ACCESSORS(jint, Int, PRIM_INT, "I"); 1570 FIELD_ACCESSORS(jlong, Long, PRIM_LONG, "J"); 1571 FIELD_ACCESSORS(jfloat, Float, PRIM_FLOAT, "F"); 1572 FIELD_ACCESSORS(jdouble, Double, PRIM_DOUBLE, "D"); 1573 1574 #define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \ 1575 /* Virtual... */ \ 1576 static _ctype Check_Call##_jname##Method(JNIEnv* env, jobject obj, \ 1577 jmethodID methodID, ...) \ 1578 { \ 1579 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \ 1580 sc.checkSig(methodID, _retsig, false); \ 1581 sc.checkVirtualMethod(obj, methodID); \ 1582 _retdecl; \ 1583 va_list args; \ 1584 va_start(args, methodID); \ 1585 _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, methodID, args); \ 1586 va_end(args); \ 1587 _retok; \ 1588 } \ 1589 static _ctype Check_Call##_jname##MethodV(JNIEnv* env, jobject obj, \ 1590 jmethodID methodID, va_list args) \ 1591 { \ 1592 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \ 1593 sc.checkSig(methodID, _retsig, false); \ 1594 sc.checkVirtualMethod(obj, methodID); \ 1595 _retdecl; \ 1596 _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, methodID, args); \ 1597 _retok; \ 1598 } \ 1599 static _ctype Check_Call##_jname##MethodA(JNIEnv* env, jobject obj, \ 1600 jmethodID methodID, jvalue* args) \ 1601 { \ 1602 CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \ 1603 sc.checkSig(methodID, _retsig, false); \ 1604 sc.checkVirtualMethod(obj, methodID); \ 1605 _retdecl; \ 1606 _retasgn baseEnv(env)->Call##_jname##MethodA(env, obj, methodID, args); \ 1607 _retok; \ 1608 } \ 1609 /* Non-virtual... */ \ 1610 static _ctype Check_CallNonvirtual##_jname##Method(JNIEnv* env, \ 1611 jobject obj, jclass clazz, jmethodID methodID, ...) \ 1612 { \ 1613 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \ 1614 sc.checkSig(methodID, _retsig, false); \ 1615 sc.checkVirtualMethod(obj, methodID); \ 1616 _retdecl; \ 1617 va_list args; \ 1618 va_start(args, methodID); \ 1619 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, methodID, args); \ 1620 va_end(args); \ 1621 _retok; \ 1622 } \ 1623 static _ctype Check_CallNonvirtual##_jname##MethodV(JNIEnv* env, \ 1624 jobject obj, jclass clazz, jmethodID methodID, va_list args) \ 1625 { \ 1626 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \ 1627 sc.checkSig(methodID, _retsig, false); \ 1628 sc.checkVirtualMethod(obj, methodID); \ 1629 _retdecl; \ 1630 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, methodID, args); \ 1631 _retok; \ 1632 } \ 1633 static _ctype Check_CallNonvirtual##_jname##MethodA(JNIEnv* env, \ 1634 jobject obj, jclass clazz, jmethodID methodID, jvalue* args) \ 1635 { \ 1636 CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \ 1637 sc.checkSig(methodID, _retsig, false); \ 1638 sc.checkVirtualMethod(obj, methodID); \ 1639 _retdecl; \ 1640 _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, clazz, methodID, args); \ 1641 _retok; \ 1642 } \ 1643 /* Static... */ \ 1644 static _ctype Check_CallStatic##_jname##Method(JNIEnv* env, \ 1645 jclass clazz, jmethodID methodID, ...) \ 1646 { \ 1647 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \ 1648 sc.checkSig(methodID, _retsig, true); \ 1649 sc.checkStaticMethod(clazz, methodID); \ 1650 _retdecl; \ 1651 va_list args; \ 1652 va_start(args, methodID); \ 1653 _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, methodID, args); \ 1654 va_end(args); \ 1655 _retok; \ 1656 } \ 1657 static _ctype Check_CallStatic##_jname##MethodV(JNIEnv* env, \ 1658 jclass clazz, jmethodID methodID, va_list args) \ 1659 { \ 1660 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \ 1661 sc.checkSig(methodID, _retsig, true); \ 1662 sc.checkStaticMethod(clazz, methodID); \ 1663 _retdecl; \ 1664 _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, methodID, args); \ 1665 _retok; \ 1666 } \ 1667 static _ctype Check_CallStatic##_jname##MethodA(JNIEnv* env, \ 1668 jclass clazz, jmethodID methodID, jvalue* args) \ 1669 { \ 1670 CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \ 1671 sc.checkSig(methodID, _retsig, true); \ 1672 sc.checkStaticMethod(clazz, methodID); \ 1673 _retdecl; \ 1674 _retasgn baseEnv(env)->CallStatic##_jname##MethodA(env, clazz, methodID, args); \ 1675 _retok; \ 1676 } 1677 1678 #define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result) 1679 #define VOID_RETURN CHECK_JNI_EXIT_VOID() 1680 1681 CALL(jobject, Object, Object* result, result=(Object*), NON_VOID_RETURN("L", jobject), "L"); 1682 CALL(jboolean, Boolean, jboolean result, result=, NON_VOID_RETURN("Z", jboolean), "Z"); 1683 CALL(jbyte, Byte, jbyte result, result=, NON_VOID_RETURN("B", jbyte), "B"); 1684 CALL(jchar, Char, jchar result, result=, NON_VOID_RETURN("C", jchar), "C"); 1685 CALL(jshort, Short, jshort result, result=, NON_VOID_RETURN("S", jshort), "S"); 1686 CALL(jint, Int, jint result, result=, NON_VOID_RETURN("I", jint), "I"); 1687 CALL(jlong, Long, jlong result, result=, NON_VOID_RETURN("J", jlong), "J"); 1688 CALL(jfloat, Float, jfloat result, result=, NON_VOID_RETURN("F", jfloat), "F"); 1689 CALL(jdouble, Double, jdouble result, result=, NON_VOID_RETURN("D", jdouble), "D"); 1690 CALL(void, Void, , , VOID_RETURN, "V"); 1691 1692 static jstring Check_NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) { 1693 CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len); 1694 return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len)); 1695 } 1696 1697 static jsize Check_GetStringLength(JNIEnv* env, jstring string) { 1698 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string); 1699 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string)); 1700 } 1701 1702 static const jchar* Check_GetStringChars(JNIEnv* env, jstring string, jboolean* isCopy) { 1703 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy); 1704 const jchar* result = baseEnv(env)->GetStringChars(env, string, isCopy); 1705 if (gDvmJni.forceCopy && result != NULL) { 1706 ScopedCheckJniThreadState ts(env); 1707 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(dvmThreadSelf(), string); 1708 int byteCount = strObj->length() * 2; 1709 result = (const jchar*) GuardedCopy::create(result, byteCount, false); 1710 if (isCopy != NULL) { 1711 *isCopy = JNI_TRUE; 1712 } 1713 } 1714 return CHECK_JNI_EXIT("p", result); 1715 } 1716 1717 static void Check_ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) { 1718 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars); 1719 sc.checkNonNull(chars); 1720 if (gDvmJni.forceCopy) { 1721 if (!GuardedCopy::check(chars, false)) { 1722 ALOGE("JNI: failed guarded copy check in ReleaseStringChars"); 1723 abortMaybe(); 1724 return; 1725 } 1726 chars = (const jchar*) GuardedCopy::destroy((jchar*)chars); 1727 } 1728 baseEnv(env)->ReleaseStringChars(env, string, chars); 1729 CHECK_JNI_EXIT_VOID(); 1730 } 1731 1732 static jstring Check_NewStringUTF(JNIEnv* env, const char* bytes) { 1733 CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string. 1734 return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes)); 1735 } 1736 1737 static jsize Check_GetStringUTFLength(JNIEnv* env, jstring string) { 1738 CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string); 1739 return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string)); 1740 } 1741 1742 static const char* Check_GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) { 1743 CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy); 1744 const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy); 1745 if (gDvmJni.forceCopy && result != NULL) { 1746 result = (const char*) GuardedCopy::create(result, strlen(result) + 1, false); 1747 if (isCopy != NULL) { 1748 *isCopy = JNI_TRUE; 1749 } 1750 } 1751 return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string. 1752 } 1753 1754 static void Check_ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) { 1755 CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string. 1756 if (gDvmJni.forceCopy) { 1757 if (!GuardedCopy::check(utf, false)) { 1758 ALOGE("JNI: failed guarded copy check in ReleaseStringUTFChars"); 1759 abortMaybe(); 1760 return; 1761 } 1762 utf = (const char*) GuardedCopy::destroy((char*)utf); 1763 } 1764 baseEnv(env)->ReleaseStringUTFChars(env, string, utf); 1765 CHECK_JNI_EXIT_VOID(); 1766 } 1767 1768 static jsize Check_GetArrayLength(JNIEnv* env, jarray array) { 1769 CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array); 1770 return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array)); 1771 } 1772 1773 static jobjectArray Check_NewObjectArray(JNIEnv* env, jsize length, 1774 jclass elementClass, jobject initialElement) 1775 { 1776 CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement); 1777 return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement)); 1778 } 1779 1780 static jobject Check_GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) { 1781 CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index); 1782 return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index)); 1783 } 1784 1785 static void Check_SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) 1786 { 1787 CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value); 1788 baseEnv(env)->SetObjectArrayElement(env, array, index, value); 1789 CHECK_JNI_EXIT_VOID(); 1790 } 1791 1792 #define NEW_PRIMITIVE_ARRAY(_artype, _jname) \ 1793 static _artype Check_New##_jname##Array(JNIEnv* env, jsize length) { \ 1794 CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \ 1795 return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \ 1796 } 1797 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean); 1798 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte); 1799 NEW_PRIMITIVE_ARRAY(jcharArray, Char); 1800 NEW_PRIMITIVE_ARRAY(jshortArray, Short); 1801 NEW_PRIMITIVE_ARRAY(jintArray, Int); 1802 NEW_PRIMITIVE_ARRAY(jlongArray, Long); 1803 NEW_PRIMITIVE_ARRAY(jfloatArray, Float); 1804 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double); 1805 1806 1807 /* 1808 * Hack to allow forcecopy to work with jniGetNonMovableArrayElements. 1809 * The code deliberately uses an invalid sequence of operations, so we 1810 * need to pass it through unmodified. Review that code before making 1811 * any changes here. 1812 */ 1813 #define kNoCopyMagic 0xd5aab57f 1814 1815 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \ 1816 static _ctype* Check_Get##_jname##ArrayElements(JNIEnv* env, \ 1817 _ctype##Array array, jboolean* isCopy) \ 1818 { \ 1819 CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \ 1820 u4 noCopy = 0; \ 1821 if (gDvmJni.forceCopy && isCopy != NULL) { \ 1822 /* capture this before the base call tramples on it */ \ 1823 noCopy = *(u4*) isCopy; \ 1824 } \ 1825 _ctype* result = baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy); \ 1826 if (gDvmJni.forceCopy && result != NULL) { \ 1827 if (noCopy == kNoCopyMagic) { \ 1828 ALOGV("FC: not copying %p %x", array, noCopy); \ 1829 } else { \ 1830 result = (_ctype*) createGuardedPACopy(env, array, isCopy); \ 1831 } \ 1832 } \ 1833 return CHECK_JNI_EXIT("p", result); \ 1834 } 1835 1836 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \ 1837 static void Check_Release##_jname##ArrayElements(JNIEnv* env, \ 1838 _ctype##Array array, _ctype* elems, jint mode) \ 1839 { \ 1840 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \ 1841 sc.checkNonNull(elems); \ 1842 if (gDvmJni.forceCopy) { \ 1843 if ((uintptr_t)elems == kNoCopyMagic) { \ 1844 ALOGV("FC: not freeing %p", array); \ 1845 elems = NULL; /* base JNI call doesn't currently need */ \ 1846 } else { \ 1847 elems = (_ctype*) releaseGuardedPACopy(env, array, elems, mode); \ 1848 } \ 1849 } \ 1850 baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \ 1851 CHECK_JNI_EXIT_VOID(); \ 1852 } 1853 1854 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \ 1855 static void Check_Get##_jname##ArrayRegion(JNIEnv* env, \ 1856 _ctype##Array array, jsize start, jsize len, _ctype* buf) { \ 1857 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \ 1858 baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \ 1859 CHECK_JNI_EXIT_VOID(); \ 1860 } 1861 1862 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \ 1863 static void Check_Set##_jname##ArrayRegion(JNIEnv* env, \ 1864 _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \ 1865 CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \ 1866 baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \ 1867 CHECK_JNI_EXIT_VOID(); \ 1868 } 1869 1870 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \ 1871 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \ 1872 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \ 1873 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \ 1874 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); 1875 1876 /* TODO: verify primitive array type matches call type */ 1877 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z'); 1878 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B'); 1879 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C'); 1880 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S'); 1881 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I'); 1882 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J'); 1883 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F'); 1884 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D'); 1885 1886 static jint Check_RegisterNatives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods, 1887 jint nMethods) 1888 { 1889 CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, clazz, methods, nMethods); 1890 return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, clazz, methods, nMethods)); 1891 } 1892 1893 static jint Check_UnregisterNatives(JNIEnv* env, jclass clazz) { 1894 CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz); 1895 return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, clazz)); 1896 } 1897 1898 static jint Check_MonitorEnter(JNIEnv* env, jobject obj) { 1899 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1900 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj)); 1901 } 1902 1903 static jint Check_MonitorExit(JNIEnv* env, jobject obj) { 1904 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj); 1905 return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj)); 1906 } 1907 1908 static jint Check_GetJavaVM(JNIEnv *env, JavaVM **vm) { 1909 CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm); 1910 return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm)); 1911 } 1912 1913 static void Check_GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) { 1914 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf); 1915 baseEnv(env)->GetStringRegion(env, str, start, len, buf); 1916 CHECK_JNI_EXIT_VOID(); 1917 } 1918 1919 static void Check_GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) { 1920 CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf); 1921 baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf); 1922 CHECK_JNI_EXIT_VOID(); 1923 } 1924 1925 static void* Check_GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) { 1926 CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy); 1927 void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy); 1928 if (gDvmJni.forceCopy && result != NULL) { 1929 result = createGuardedPACopy(env, array, isCopy); 1930 } 1931 return CHECK_JNI_EXIT("p", result); 1932 } 1933 1934 static void Check_ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) 1935 { 1936 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode); 1937 sc.checkNonNull(carray); 1938 if (gDvmJni.forceCopy) { 1939 carray = releaseGuardedPACopy(env, array, carray, mode); 1940 } 1941 baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode); 1942 CHECK_JNI_EXIT_VOID(); 1943 } 1944 1945 static const jchar* Check_GetStringCritical(JNIEnv* env, jstring string, jboolean* isCopy) { 1946 CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, string, isCopy); 1947 const jchar* result = baseEnv(env)->GetStringCritical(env, string, isCopy); 1948 if (gDvmJni.forceCopy && result != NULL) { 1949 ScopedCheckJniThreadState ts(env); 1950 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(dvmThreadSelf(), string); 1951 int byteCount = strObj->length() * 2; 1952 result = (const jchar*) GuardedCopy::create(result, byteCount, false); 1953 if (isCopy != NULL) { 1954 *isCopy = JNI_TRUE; 1955 } 1956 } 1957 return CHECK_JNI_EXIT("p", result); 1958 } 1959 1960 static void Check_ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) { 1961 CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray); 1962 sc.checkNonNull(carray); 1963 if (gDvmJni.forceCopy) { 1964 if (!GuardedCopy::check(carray, false)) { 1965 ALOGE("JNI: failed guarded copy check in ReleaseStringCritical"); 1966 abortMaybe(); 1967 return; 1968 } 1969 carray = (const jchar*) GuardedCopy::destroy((jchar*)carray); 1970 } 1971 baseEnv(env)->ReleaseStringCritical(env, string, carray); 1972 CHECK_JNI_EXIT_VOID(); 1973 } 1974 1975 static jweak Check_NewWeakGlobalRef(JNIEnv* env, jobject obj) { 1976 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1977 return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj)); 1978 } 1979 1980 static void Check_DeleteWeakGlobalRef(JNIEnv* env, jweak obj) { 1981 CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj); 1982 baseEnv(env)->DeleteWeakGlobalRef(env, obj); 1983 CHECK_JNI_EXIT_VOID(); 1984 } 1985 1986 static jboolean Check_ExceptionCheck(JNIEnv* env) { 1987 CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env); 1988 return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env)); 1989 } 1990 1991 static jobjectRefType Check_GetObjectRefType(JNIEnv* env, jobject obj) { 1992 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj); 1993 // TODO: proper decoding of jobjectRefType! 1994 return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj)); 1995 } 1996 1997 static jobject Check_NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) { 1998 CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity); 1999 return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity)); 2000 } 2001 2002 static void* Check_GetDirectBufferAddress(JNIEnv* env, jobject buf) { 2003 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf); 2004 // TODO: check that 'buf' is a java.nio.Buffer. 2005 return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf)); 2006 } 2007 2008 static jlong Check_GetDirectBufferCapacity(JNIEnv* env, jobject buf) { 2009 CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf); 2010 // TODO: check that 'buf' is a java.nio.Buffer. 2011 return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf)); 2012 } 2013 2014 2015 /* 2016 * =========================================================================== 2017 * JNI invocation functions 2018 * =========================================================================== 2019 */ 2020 2021 static jint Check_DestroyJavaVM(JavaVM* vm) { 2022 ScopedCheck sc(false, __FUNCTION__); 2023 sc.check(true, "v", vm); 2024 return CHECK_JNI_EXIT("I", baseVm(vm)->DestroyJavaVM(vm)); 2025 } 2026 2027 static jint Check_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) { 2028 ScopedCheck sc(false, __FUNCTION__); 2029 sc.check(true, "vpt", vm, p_env, thr_args); 2030 return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThread(vm, p_env, thr_args)); 2031 } 2032 2033 static jint Check_AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) { 2034 ScopedCheck sc(false, __FUNCTION__); 2035 sc.check(true, "vpt", vm, p_env, thr_args); 2036 return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args)); 2037 } 2038 2039 static jint Check_DetachCurrentThread(JavaVM* vm) { 2040 ScopedCheck sc(true, __FUNCTION__); 2041 sc.check(true, "v", vm); 2042 return CHECK_JNI_EXIT("I", baseVm(vm)->DetachCurrentThread(vm)); 2043 } 2044 2045 static jint Check_GetEnv(JavaVM* vm, void** env, jint version) { 2046 ScopedCheck sc(true, __FUNCTION__); 2047 sc.check(true, "v", vm); 2048 return CHECK_JNI_EXIT("I", baseVm(vm)->GetEnv(vm, env, version)); 2049 } 2050 2051 2052 /* 2053 * =========================================================================== 2054 * Function tables 2055 * =========================================================================== 2056 */ 2057 2058 static const struct JNINativeInterface gCheckNativeInterface = { 2059 NULL, 2060 NULL, 2061 NULL, 2062 NULL, 2063 2064 Check_GetVersion, 2065 2066 Check_DefineClass, 2067 Check_FindClass, 2068 2069 Check_FromReflectedMethod, 2070 Check_FromReflectedField, 2071 Check_ToReflectedMethod, 2072 2073 Check_GetSuperclass, 2074 Check_IsAssignableFrom, 2075 2076 Check_ToReflectedField, 2077 2078 Check_Throw, 2079 Check_ThrowNew, 2080 Check_ExceptionOccurred, 2081 Check_ExceptionDescribe, 2082 Check_ExceptionClear, 2083 Check_FatalError, 2084 2085 Check_PushLocalFrame, 2086 Check_PopLocalFrame, 2087 2088 Check_NewGlobalRef, 2089 Check_DeleteGlobalRef, 2090 Check_DeleteLocalRef, 2091 Check_IsSameObject, 2092 Check_NewLocalRef, 2093 Check_EnsureLocalCapacity, 2094 2095 Check_AllocObject, 2096 Check_NewObject, 2097 Check_NewObjectV, 2098 Check_NewObjectA, 2099 2100 Check_GetObjectClass, 2101 Check_IsInstanceOf, 2102 2103 Check_GetMethodID, 2104 2105 Check_CallObjectMethod, 2106 Check_CallObjectMethodV, 2107 Check_CallObjectMethodA, 2108 Check_CallBooleanMethod, 2109 Check_CallBooleanMethodV, 2110 Check_CallBooleanMethodA, 2111 Check_CallByteMethod, 2112 Check_CallByteMethodV, 2113 Check_CallByteMethodA, 2114 Check_CallCharMethod, 2115 Check_CallCharMethodV, 2116 Check_CallCharMethodA, 2117 Check_CallShortMethod, 2118 Check_CallShortMethodV, 2119 Check_CallShortMethodA, 2120 Check_CallIntMethod, 2121 Check_CallIntMethodV, 2122 Check_CallIntMethodA, 2123 Check_CallLongMethod, 2124 Check_CallLongMethodV, 2125 Check_CallLongMethodA, 2126 Check_CallFloatMethod, 2127 Check_CallFloatMethodV, 2128 Check_CallFloatMethodA, 2129 Check_CallDoubleMethod, 2130 Check_CallDoubleMethodV, 2131 Check_CallDoubleMethodA, 2132 Check_CallVoidMethod, 2133 Check_CallVoidMethodV, 2134 Check_CallVoidMethodA, 2135 2136 Check_CallNonvirtualObjectMethod, 2137 Check_CallNonvirtualObjectMethodV, 2138 Check_CallNonvirtualObjectMethodA, 2139 Check_CallNonvirtualBooleanMethod, 2140 Check_CallNonvirtualBooleanMethodV, 2141 Check_CallNonvirtualBooleanMethodA, 2142 Check_CallNonvirtualByteMethod, 2143 Check_CallNonvirtualByteMethodV, 2144 Check_CallNonvirtualByteMethodA, 2145 Check_CallNonvirtualCharMethod, 2146 Check_CallNonvirtualCharMethodV, 2147 Check_CallNonvirtualCharMethodA, 2148 Check_CallNonvirtualShortMethod, 2149 Check_CallNonvirtualShortMethodV, 2150 Check_CallNonvirtualShortMethodA, 2151 Check_CallNonvirtualIntMethod, 2152 Check_CallNonvirtualIntMethodV, 2153 Check_CallNonvirtualIntMethodA, 2154 Check_CallNonvirtualLongMethod, 2155 Check_CallNonvirtualLongMethodV, 2156 Check_CallNonvirtualLongMethodA, 2157 Check_CallNonvirtualFloatMethod, 2158 Check_CallNonvirtualFloatMethodV, 2159 Check_CallNonvirtualFloatMethodA, 2160 Check_CallNonvirtualDoubleMethod, 2161 Check_CallNonvirtualDoubleMethodV, 2162 Check_CallNonvirtualDoubleMethodA, 2163 Check_CallNonvirtualVoidMethod, 2164 Check_CallNonvirtualVoidMethodV, 2165 Check_CallNonvirtualVoidMethodA, 2166 2167 Check_GetFieldID, 2168 2169 Check_GetObjectField, 2170 Check_GetBooleanField, 2171 Check_GetByteField, 2172 Check_GetCharField, 2173 Check_GetShortField, 2174 Check_GetIntField, 2175 Check_GetLongField, 2176 Check_GetFloatField, 2177 Check_GetDoubleField, 2178 Check_SetObjectField, 2179 Check_SetBooleanField, 2180 Check_SetByteField, 2181 Check_SetCharField, 2182 Check_SetShortField, 2183 Check_SetIntField, 2184 Check_SetLongField, 2185 Check_SetFloatField, 2186 Check_SetDoubleField, 2187 2188 Check_GetStaticMethodID, 2189 2190 Check_CallStaticObjectMethod, 2191 Check_CallStaticObjectMethodV, 2192 Check_CallStaticObjectMethodA, 2193 Check_CallStaticBooleanMethod, 2194 Check_CallStaticBooleanMethodV, 2195 Check_CallStaticBooleanMethodA, 2196 Check_CallStaticByteMethod, 2197 Check_CallStaticByteMethodV, 2198 Check_CallStaticByteMethodA, 2199 Check_CallStaticCharMethod, 2200 Check_CallStaticCharMethodV, 2201 Check_CallStaticCharMethodA, 2202 Check_CallStaticShortMethod, 2203 Check_CallStaticShortMethodV, 2204 Check_CallStaticShortMethodA, 2205 Check_CallStaticIntMethod, 2206 Check_CallStaticIntMethodV, 2207 Check_CallStaticIntMethodA, 2208 Check_CallStaticLongMethod, 2209 Check_CallStaticLongMethodV, 2210 Check_CallStaticLongMethodA, 2211 Check_CallStaticFloatMethod, 2212 Check_CallStaticFloatMethodV, 2213 Check_CallStaticFloatMethodA, 2214 Check_CallStaticDoubleMethod, 2215 Check_CallStaticDoubleMethodV, 2216 Check_CallStaticDoubleMethodA, 2217 Check_CallStaticVoidMethod, 2218 Check_CallStaticVoidMethodV, 2219 Check_CallStaticVoidMethodA, 2220 2221 Check_GetStaticFieldID, 2222 2223 Check_GetStaticObjectField, 2224 Check_GetStaticBooleanField, 2225 Check_GetStaticByteField, 2226 Check_GetStaticCharField, 2227 Check_GetStaticShortField, 2228 Check_GetStaticIntField, 2229 Check_GetStaticLongField, 2230 Check_GetStaticFloatField, 2231 Check_GetStaticDoubleField, 2232 2233 Check_SetStaticObjectField, 2234 Check_SetStaticBooleanField, 2235 Check_SetStaticByteField, 2236 Check_SetStaticCharField, 2237 Check_SetStaticShortField, 2238 Check_SetStaticIntField, 2239 Check_SetStaticLongField, 2240 Check_SetStaticFloatField, 2241 Check_SetStaticDoubleField, 2242 2243 Check_NewString, 2244 2245 Check_GetStringLength, 2246 Check_GetStringChars, 2247 Check_ReleaseStringChars, 2248 2249 Check_NewStringUTF, 2250 Check_GetStringUTFLength, 2251 Check_GetStringUTFChars, 2252 Check_ReleaseStringUTFChars, 2253 2254 Check_GetArrayLength, 2255 Check_NewObjectArray, 2256 Check_GetObjectArrayElement, 2257 Check_SetObjectArrayElement, 2258 2259 Check_NewBooleanArray, 2260 Check_NewByteArray, 2261 Check_NewCharArray, 2262 Check_NewShortArray, 2263 Check_NewIntArray, 2264 Check_NewLongArray, 2265 Check_NewFloatArray, 2266 Check_NewDoubleArray, 2267 2268 Check_GetBooleanArrayElements, 2269 Check_GetByteArrayElements, 2270 Check_GetCharArrayElements, 2271 Check_GetShortArrayElements, 2272 Check_GetIntArrayElements, 2273 Check_GetLongArrayElements, 2274 Check_GetFloatArrayElements, 2275 Check_GetDoubleArrayElements, 2276 2277 Check_ReleaseBooleanArrayElements, 2278 Check_ReleaseByteArrayElements, 2279 Check_ReleaseCharArrayElements, 2280 Check_ReleaseShortArrayElements, 2281 Check_ReleaseIntArrayElements, 2282 Check_ReleaseLongArrayElements, 2283 Check_ReleaseFloatArrayElements, 2284 Check_ReleaseDoubleArrayElements, 2285 2286 Check_GetBooleanArrayRegion, 2287 Check_GetByteArrayRegion, 2288 Check_GetCharArrayRegion, 2289 Check_GetShortArrayRegion, 2290 Check_GetIntArrayRegion, 2291 Check_GetLongArrayRegion, 2292 Check_GetFloatArrayRegion, 2293 Check_GetDoubleArrayRegion, 2294 Check_SetBooleanArrayRegion, 2295 Check_SetByteArrayRegion, 2296 Check_SetCharArrayRegion, 2297 Check_SetShortArrayRegion, 2298 Check_SetIntArrayRegion, 2299 Check_SetLongArrayRegion, 2300 Check_SetFloatArrayRegion, 2301 Check_SetDoubleArrayRegion, 2302 2303 Check_RegisterNatives, 2304 Check_UnregisterNatives, 2305 2306 Check_MonitorEnter, 2307 Check_MonitorExit, 2308 2309 Check_GetJavaVM, 2310 2311 Check_GetStringRegion, 2312 Check_GetStringUTFRegion, 2313 2314 Check_GetPrimitiveArrayCritical, 2315 Check_ReleasePrimitiveArrayCritical, 2316 2317 Check_GetStringCritical, 2318 Check_ReleaseStringCritical, 2319 2320 Check_NewWeakGlobalRef, 2321 Check_DeleteWeakGlobalRef, 2322 2323 Check_ExceptionCheck, 2324 2325 Check_NewDirectByteBuffer, 2326 Check_GetDirectBufferAddress, 2327 Check_GetDirectBufferCapacity, 2328 2329 Check_GetObjectRefType 2330 }; 2331 2332 static const struct JNIInvokeInterface gCheckInvokeInterface = { 2333 NULL, 2334 NULL, 2335 NULL, 2336 2337 Check_DestroyJavaVM, 2338 Check_AttachCurrentThread, 2339 Check_DetachCurrentThread, 2340 2341 Check_GetEnv, 2342 2343 Check_AttachCurrentThreadAsDaemon, 2344 }; 2345 2346 /* 2347 * Replace the normal table with the checked table. 2348 */ 2349 void dvmUseCheckedJniEnv(JNIEnvExt* pEnv) { 2350 assert(pEnv->funcTable != &gCheckNativeInterface); 2351 pEnv->baseFuncTable = pEnv->funcTable; 2352 pEnv->funcTable = &gCheckNativeInterface; 2353 } 2354 2355 /* 2356 * Replace the normal table with the checked table. 2357 */ 2358 void dvmUseCheckedJniVm(JavaVMExt* pVm) { 2359 assert(pVm->funcTable != &gCheckInvokeInterface); 2360 pVm->baseFuncTable = pVm->funcTable; 2361 pVm->funcTable = &gCheckInvokeInterface; 2362 } 2363