/* * Generate the contents of a THST chunk. The data encompasses all known * threads. * * Response has: * (1b) header len * (1b) bytes per entry * (2b) thread count * Then, for each thread: * (4b) threadId * (1b) thread status * (4b) tid * (4b) utime * (4b) stime * (1b) is daemon? * * The length fields exist in anticipation of adding additional fields * without wanting to break ddms or bump the full protocol version. I don't * think it warrants full versioning. They might be extraneous and could * be removed from a future version. * * Returns a new byte[] with the data inside, or NULL on failure. The * caller must call dvmReleaseTrackedAlloc() on the array. */ ArrayObject* dvmDdmGenerateThreadStats(void) { const int kHeaderLen = 4; const int kBytesPerEntry = 18; dvmLockThreadList(NULL); Thread* thread; int threadCount = 0; for (thread = gDvm.threadList; thread != NULL; thread = thread->next) threadCount++; /* * Create a temporary buffer. We can't perform heap allocation with * the thread list lock held (could cause a GC). The output is small * enough to sit on the stack. */ int bufLen = kHeaderLen + threadCount * kBytesPerEntry; u1 tmpBuf[bufLen]; u1* buf = tmpBuf; set1(buf+0, kHeaderLen); set1(buf+1, kBytesPerEntry); set2BE(buf+2, (u2) threadCount); buf += kHeaderLen; pid_t pid = getpid(); for (thread = gDvm.threadList; thread != NULL; thread = thread->next) { unsigned long utime, stime; bool isDaemon; if (!getThreadStats(pid, thread->systemTid, &utime, &stime)) { // failed; drop in empty values utime = stime = 0; } isDaemon = dvmGetFieldBoolean(thread->threadObj, gDvm.offJavaLangThread_daemon); set4BE(buf+0, thread->threadId); set1(buf+4, thread->status); set4BE(buf+5, thread->systemTid); set4BE(buf+9, utime); set4BE(buf+13, stime); set1(buf+17, isDaemon); buf += kBytesPerEntry; } dvmUnlockThreadList(); /* * Create a byte array to hold the data. */ ArrayObject* arrayObj = dvmAllocPrimitiveArray('B', bufLen, ALLOC_DEFAULT); if (arrayObj != NULL) memcpy(arrayObj->contents, tmpBuf, bufLen); return arrayObj; }
/* * Dump some information about an object. */ void dvmDumpObject(const Object* obj) { ClassObject* clazz; int i; if (obj == NULL || obj->clazz == NULL) { LOGW("Null or malformed object not dumped\n"); return; } clazz = obj->clazz; LOGD("----- Object dump: %p (%s, %d bytes) -----\n", obj, clazz->descriptor, (int) clazz->objectSize); //printHexDump(obj, clazz->objectSize); LOGD(" Fields:\n"); while (clazz != NULL) { LOGD(" -- %s\n", clazz->descriptor); for (i = 0; i < clazz->ifieldCount; i++) { const InstField* pField = &clazz->ifields[i]; char type = pField->field.signature[0]; if (type == 'F' || type == 'D') { double dval; if (type == 'F') dval = dvmGetFieldFloat(obj, pField->byteOffset); else dval = dvmGetFieldDouble(obj, pField->byteOffset); LOGD(" %2d: '%s' '%s' af=%04x off=%d %.3f\n", i, pField->field.name, pField->field.signature, pField->field.accessFlags, pField->byteOffset, dval); } else { u8 lval; if (type == 'J') lval = dvmGetFieldLong(obj, pField->byteOffset); else if (type == 'Z') lval = dvmGetFieldBoolean(obj, pField->byteOffset); else lval = dvmGetFieldInt(obj, pField->byteOffset); LOGD(" %2d: '%s' '%s' af=%04x off=%d 0x%08llx\n", i, pField->field.name, pField->field.signature, pField->field.accessFlags, pField->byteOffset, lval); } } clazz = clazz->super; } }
/* * dump一些关于某个对象的信息 * */ void dvmDumpObject(const Object* obj) { ClassObject* clazz; int i; if (obj == NULL || obj->clazz == NULL) { ALOGW("Null or malformed object not dumped"); return; } clazz = obj->clazz; ALOGD("----- Object dump: %p (%s, %d bytes) -----", obj, clazz->descriptor, (int) clazz->objectSize); //printHexDump(obj, clazz->objectSize); ALOGD(" Fields:"); while (clazz != NULL) { ALOGD(" -- %s", clazz->descriptor); for (i = 0; i < clazz->ifieldCount; i++) { const InstField* pField = &clazz->ifields[i]; char type = pField->signature[0]; if (type == 'F' || type == 'D') { double dval; if (type == 'F') dval = dvmGetFieldFloat(obj, pField->byteOffset); else dval = dvmGetFieldDouble(obj, pField->byteOffset); ALOGD(" %2d: '%s' '%s' af=%04x off=%d %.3f", i, pField->name, pField->signature, pField->accessFlags, pField->byteOffset, dval); } else { u8 lval; if (type == 'J') lval = dvmGetFieldLong(obj, pField->byteOffset); else if (type == 'Z') lval = dvmGetFieldBoolean(obj, pField->byteOffset); else lval = dvmGetFieldInt(obj, pField->byteOffset); ALOGD(" %2d: '%s' '%s' af=%04x off=%d 0x%08llx", i, pField->name, pField->signature, pField->accessFlags, pField->byteOffset, lval); } } clazz = clazz->super; } if (dvmIsClassObject(obj)) { ALOGD(" Static fields:"); const StaticField* sfields = &((ClassObject *)obj)->sfields[0]; for (i = 0; i < ((ClassObject *)obj)->sfieldCount; ++i) { const StaticField* pField = &sfields[i]; size_t byteOffset = (size_t)pField - (size_t)sfields; char type = pField->signature[0]; if (type == 'F' || type == 'D') { double dval; if (type == 'F') dval = pField->value.f; else dval = pField->value.d; ALOGD(" %2d: '%s' '%s' af=%04x off=%zd %.3f", i, pField->name, pField->signature, pField->accessFlags, byteOffset, dval); } else { u8 lval; if (type == 'J') lval = pField->value.j; else if (type == 'Z') lval = pField->value.z; else lval = pField->value.i; ALOGD(" %2d: '%s' '%s' af=%04x off=%zd 0x%08llx", i, pField->name, pField->signature, pField->accessFlags, byteOffset, lval); } } } }