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 * dalvik.system.VMDebug
19 */
20 #include "Dalvik.h"
21 #include "alloc/HeapSource.h"
22 #include "native/InternalNativePriv.h"
23 #include "hprof/Hprof.h"
24
25 #include <string.h>
26 #include <unistd.h>
27
28
29 /*
30 * Extracts the fd from a FileDescriptor object.
31 *
32 * If an error is encountered, or the extracted descriptor is numerically
33 * invalid, this returns -1 with an exception raised.
34 */
getFileDescriptor(Object * obj)35 static int getFileDescriptor(Object* obj)
36 {
37 assert(obj != NULL);
38 assert(strcmp(obj->clazz->descriptor, "Ljava/io/FileDescriptor;") == 0);
39
40 int fd = dvmGetFieldInt(obj, gDvm.offJavaIoFileDescriptor_descriptor);
41 if (fd < 0) {
42 dvmThrowRuntimeException("Invalid file descriptor");
43 return -1;
44 }
45
46 return fd;
47 }
48
49 /*
50 * static String[] getVmFeatureList()
51 *
52 * Return a set of strings describing available VM features (this is chiefly
53 * of interest to DDMS).
54 */
Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4 * args,JValue * pResult)55 static void Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4* args, JValue* pResult) {
56 std::vector<std::string> features;
57 features.push_back("method-trace-profiling");
58 features.push_back("method-trace-profiling-streaming");
59 features.push_back("method-sample-profiling");
60 features.push_back("hprof-heap-dump");
61 features.push_back("hprof-heap-dump-streaming");
62
63 ArrayObject* result = dvmCreateStringArray(features);
64 dvmReleaseTrackedAlloc((Object*) result, dvmThreadSelf());
65 RETURN_PTR(result);
66 }
67
68 /* These must match the values in dalvik.system.VMDebug.
69 */
70 enum {
71 KIND_ALLOCATED_OBJECTS = 1<<0,
72 KIND_ALLOCATED_BYTES = 1<<1,
73 KIND_FREED_OBJECTS = 1<<2,
74 KIND_FREED_BYTES = 1<<3,
75 KIND_GC_INVOCATIONS = 1<<4,
76 KIND_CLASS_INIT_COUNT = 1<<5,
77 KIND_CLASS_INIT_TIME = 1<<6,
78
79 /* These values exist for backward compatibility. */
80 KIND_EXT_ALLOCATED_OBJECTS = 1<<12,
81 KIND_EXT_ALLOCATED_BYTES = 1<<13,
82 KIND_EXT_FREED_OBJECTS = 1<<14,
83 KIND_EXT_FREED_BYTES = 1<<15,
84
85 KIND_GLOBAL_ALLOCATED_OBJECTS = KIND_ALLOCATED_OBJECTS,
86 KIND_GLOBAL_ALLOCATED_BYTES = KIND_ALLOCATED_BYTES,
87 KIND_GLOBAL_FREED_OBJECTS = KIND_FREED_OBJECTS,
88 KIND_GLOBAL_FREED_BYTES = KIND_FREED_BYTES,
89 KIND_GLOBAL_GC_INVOCATIONS = KIND_GC_INVOCATIONS,
90 KIND_GLOBAL_CLASS_INIT_COUNT = KIND_CLASS_INIT_COUNT,
91 KIND_GLOBAL_CLASS_INIT_TIME = KIND_CLASS_INIT_TIME,
92
93 KIND_THREAD_ALLOCATED_OBJECTS = KIND_ALLOCATED_OBJECTS << 16,
94 KIND_THREAD_ALLOCATED_BYTES = KIND_ALLOCATED_BYTES << 16,
95 KIND_THREAD_FREED_OBJECTS = KIND_FREED_OBJECTS << 16,
96 KIND_THREAD_FREED_BYTES = KIND_FREED_BYTES << 16,
97
98 KIND_THREAD_GC_INVOCATIONS = KIND_GC_INVOCATIONS << 16,
99
100 // TODO: failedAllocCount, failedAllocSize
101 };
102
103 #define KIND_ALL_COUNTS 0xffffffff
104
105 /*
106 * Zero out the specified fields.
107 */
clearAllocProfStateFields(AllocProfState * allocProf,unsigned int kinds)108 static void clearAllocProfStateFields(AllocProfState *allocProf,
109 unsigned int kinds)
110 {
111 if (kinds & KIND_ALLOCATED_OBJECTS) {
112 allocProf->allocCount = 0;
113 }
114 if (kinds & KIND_ALLOCATED_BYTES) {
115 allocProf->allocSize = 0;
116 }
117 if (kinds & KIND_FREED_OBJECTS) {
118 allocProf->freeCount = 0;
119 }
120 if (kinds & KIND_FREED_BYTES) {
121 allocProf->freeSize = 0;
122 }
123 if (kinds & KIND_GC_INVOCATIONS) {
124 allocProf->gcCount = 0;
125 }
126 if (kinds & KIND_CLASS_INIT_COUNT) {
127 allocProf->classInitCount = 0;
128 }
129 if (kinds & KIND_CLASS_INIT_TIME) {
130 allocProf->classInitTime = 0;
131 }
132 }
133
134 /*
135 * static void startAllocCounting()
136 *
137 * Reset the counters and enable counting.
138 *
139 * TODO: this currently only resets the per-thread counters for the current
140 * thread. If we actually start using the per-thread counters we'll
141 * probably want to fix this.
142 */
Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4 * args,JValue * pResult)143 static void Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4* args,
144 JValue* pResult)
145 {
146 UNUSED_PARAMETER(args);
147
148 clearAllocProfStateFields(&gDvm.allocProf, KIND_ALL_COUNTS);
149 clearAllocProfStateFields(&dvmThreadSelf()->allocProf, KIND_ALL_COUNTS);
150 dvmStartAllocCounting();
151 RETURN_VOID();
152 }
153
154 /*
155 * public static void stopAllocCounting()
156 */
Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4 * args,JValue * pResult)157 static void Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4* args,
158 JValue* pResult)
159 {
160 UNUSED_PARAMETER(args);
161
162 dvmStopAllocCounting();
163 RETURN_VOID();
164 }
165
166 /*
167 * private static int getAllocCount(int kind)
168 */
Dalvik_dalvik_system_VMDebug_getAllocCount(const u4 * args,JValue * pResult)169 static void Dalvik_dalvik_system_VMDebug_getAllocCount(const u4* args,
170 JValue* pResult)
171 {
172 AllocProfState *allocProf;
173 unsigned int kind = args[0];
174 if (kind < (1<<16)) {
175 allocProf = &gDvm.allocProf;
176 } else {
177 allocProf = &dvmThreadSelf()->allocProf;
178 kind >>= 16;
179 }
180 switch (kind) {
181 case KIND_ALLOCATED_OBJECTS:
182 pResult->i = allocProf->allocCount;
183 break;
184 case KIND_ALLOCATED_BYTES:
185 pResult->i = allocProf->allocSize;
186 break;
187 case KIND_FREED_OBJECTS:
188 pResult->i = allocProf->freeCount;
189 break;
190 case KIND_FREED_BYTES:
191 pResult->i = allocProf->freeSize;
192 break;
193 case KIND_GC_INVOCATIONS:
194 pResult->i = allocProf->gcCount;
195 break;
196 case KIND_CLASS_INIT_COUNT:
197 pResult->i = allocProf->classInitCount;
198 break;
199 case KIND_CLASS_INIT_TIME:
200 /* convert nsec to usec, reduce to 32 bits */
201 pResult->i = (int) (allocProf->classInitTime / 1000);
202 break;
203 case KIND_EXT_ALLOCATED_OBJECTS:
204 case KIND_EXT_ALLOCATED_BYTES:
205 case KIND_EXT_FREED_OBJECTS:
206 case KIND_EXT_FREED_BYTES:
207 pResult->i = 0; /* backward compatibility */
208 break;
209 default:
210 assert(false);
211 pResult->i = -1;
212 }
213 }
214
215 /*
216 * public static void resetAllocCount(int kinds)
217 */
Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4 * args,JValue * pResult)218 static void Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4* args,
219 JValue* pResult)
220 {
221 unsigned int kinds = args[0];
222 clearAllocProfStateFields(&gDvm.allocProf, kinds & 0xffff);
223 clearAllocProfStateFields(&dvmThreadSelf()->allocProf, kinds >> 16);
224 RETURN_VOID();
225 }
226
227 /*
228 * static void startMethodTracingDdmsImpl(int bufferSize, int flags,
229 * boolean samplingEnabled, int intervalUs)
230 *
231 * Start method trace profiling, sending results directly to DDMS.
232 */
Dalvik_dalvik_system_VMDebug_startMethodTracingDdmsImpl(const u4 * args,JValue * pResult)233 static void Dalvik_dalvik_system_VMDebug_startMethodTracingDdmsImpl(const u4* args,
234 JValue* pResult)
235 {
236 int bufferSize = args[0];
237 int flags = args[1];
238 bool samplingEnabled = args[2];
239 int intervalUs = args[3];
240 dvmMethodTraceStart("[DDMS]", -1, bufferSize, flags, true, samplingEnabled,
241 intervalUs);
242 RETURN_VOID();
243 }
244
245 /*
246 * static void startMethodTracingFd(String traceFileName, FileDescriptor fd,
247 * int bufferSize, int flags)
248 *
249 * Start method trace profiling, sending results to a file descriptor.
250 */
Dalvik_dalvik_system_VMDebug_startMethodTracingFd(const u4 * args,JValue * pResult)251 static void Dalvik_dalvik_system_VMDebug_startMethodTracingFd(const u4* args,
252 JValue* pResult)
253 {
254 StringObject* traceFileStr = (StringObject*) args[0];
255 Object* traceFd = (Object*) args[1];
256 int bufferSize = args[2];
257 int flags = args[3];
258
259 int origFd = getFileDescriptor(traceFd);
260 if (origFd < 0)
261 RETURN_VOID();
262
263 int fd = dup(origFd);
264 if (fd < 0) {
265 dvmThrowExceptionFmt(gDvm.exRuntimeException,
266 "dup(%d) failed: %s", origFd, strerror(errno));
267 RETURN_VOID();
268 }
269
270 char* traceFileName = dvmCreateCstrFromString(traceFileStr);
271 if (traceFileName == NULL) {
272 RETURN_VOID();
273 }
274
275 dvmMethodTraceStart(traceFileName, fd, bufferSize, flags, false, false, 0);
276 free(traceFileName);
277 RETURN_VOID();
278 }
279
280 /*
281 * static void startMethodTracingFilename(String traceFileName, int bufferSize,
282 * int flags)
283 *
284 * Start method trace profiling, sending results to a file.
285 */
Dalvik_dalvik_system_VMDebug_startMethodTracingFilename(const u4 * args,JValue * pResult)286 static void Dalvik_dalvik_system_VMDebug_startMethodTracingFilename(const u4* args,
287 JValue* pResult)
288 {
289 StringObject* traceFileStr = (StringObject*) args[0];
290 int bufferSize = args[1];
291 int flags = args[2];
292
293 char* traceFileName = dvmCreateCstrFromString(traceFileStr);
294 if (traceFileName == NULL) {
295 RETURN_VOID();
296 }
297
298 dvmMethodTraceStart(traceFileName, -1, bufferSize, flags, false, false, 0);
299 free(traceFileName);
300 RETURN_VOID();
301 }
302
303 /*
304 * static int getMethodTracingMode()
305 *
306 * Determine whether method tracing is currently active and what type is active.
307 */
Dalvik_dalvik_system_VMDebug_getMethodTracingMode(const u4 * args,JValue * pResult)308 static void Dalvik_dalvik_system_VMDebug_getMethodTracingMode(const u4* args,
309 JValue* pResult)
310 {
311 UNUSED_PARAMETER(args);
312
313 RETURN_INT(dvmGetMethodTracingMode());
314 }
315
316 /*
317 * static void stopMethodTracing()
318 *
319 * Stop method tracing.
320 */
Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4 * args,JValue * pResult)321 static void Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4* args,
322 JValue* pResult)
323 {
324 UNUSED_PARAMETER(args);
325
326 dvmMethodTraceStop();
327 RETURN_VOID();
328 }
329
330 /*
331 * static void startEmulatorTracing()
332 *
333 * Start sending method trace info to the emulator.
334 */
Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4 * args,JValue * pResult)335 static void Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4* args,
336 JValue* pResult)
337 {
338 UNUSED_PARAMETER(args);
339
340 dvmEmulatorTraceStart();
341 RETURN_VOID();
342 }
343
344 /*
345 * static void stopEmulatorTracing()
346 *
347 * Start sending method trace info to the emulator.
348 */
Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4 * args,JValue * pResult)349 static void Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4* args,
350 JValue* pResult)
351 {
352 UNUSED_PARAMETER(args);
353
354 dvmEmulatorTraceStop();
355 RETURN_VOID();
356 }
357
358 /*
359 * static boolean isDebuggerConnected()
360 *
361 * Returns "true" if a debugger is attached.
362 */
Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4 * args,JValue * pResult)363 static void Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4* args,
364 JValue* pResult)
365 {
366 UNUSED_PARAMETER(args);
367
368 RETURN_BOOLEAN(dvmDbgIsDebuggerConnected());
369 }
370
371 /*
372 * static boolean isDebuggingEnabled()
373 *
374 * Returns "true" if debugging is enabled.
375 */
Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4 * args,JValue * pResult)376 static void Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4* args,
377 JValue* pResult)
378 {
379 UNUSED_PARAMETER(args);
380
381 RETURN_BOOLEAN(gDvm.jdwpConfigured);
382 }
383
384 /*
385 * static long lastDebuggerActivity()
386 *
387 * Returns the time, in msec, since we last had an interaction with the
388 * debugger (send or receive).
389 */
Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4 * args,JValue * pResult)390 static void Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4* args,
391 JValue* pResult)
392 {
393 UNUSED_PARAMETER(args);
394
395 RETURN_LONG(dvmDbgLastDebuggerActivity());
396 }
397
398 /*
399 * static void startInstructionCounting()
400 */
Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4 * args,JValue * pResult)401 static void Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4* args,
402 JValue* pResult)
403 {
404 dvmStartInstructionCounting();
405 RETURN_VOID();
406 }
407
408 /*
409 * static void stopInstructionCounting()
410 */
Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4 * args,JValue * pResult)411 static void Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4* args,
412 JValue* pResult)
413 {
414 dvmStopInstructionCounting();
415 RETURN_VOID();
416 }
417
418 /*
419 * static boolean getInstructionCount(int[] counts)
420 *
421 * Grab a copy of the global instruction count array.
422 *
423 * Since the instruction counts aren't synchronized, we use sched_yield
424 * to improve our chances of finishing without contention. (Only makes
425 * sense on a uniprocessor.)
426 */
Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4 * args,JValue * pResult)427 static void Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4* args,
428 JValue* pResult)
429 {
430 ArrayObject* countArray = (ArrayObject*) args[0];
431
432 if (countArray != NULL) {
433 int* storage = (int*)(void*)countArray->contents;
434 u4 length = countArray->length;
435
436 /*
437 * Ensure that we copy at most kNumPackedOpcodes
438 * elements, but no more than the length of the given array.
439 */
440 if (length > kNumPackedOpcodes) {
441 length = kNumPackedOpcodes;
442 }
443
444 sched_yield();
445 memcpy(storage, gDvm.executedInstrCounts, length * sizeof(int));
446 }
447
448 RETURN_VOID();
449 }
450
451 /*
452 * static boolean resetInstructionCount()
453 *
454 * Reset the instruction count array.
455 */
Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4 * args,JValue * pResult)456 static void Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4* args,
457 JValue* pResult)
458 {
459 sched_yield();
460 memset(gDvm.executedInstrCounts, 0, kNumPackedOpcodes * sizeof(int));
461 RETURN_VOID();
462 }
463
464 /*
465 * static void printLoadedClasses(int flags)
466 *
467 * Dump the list of loaded classes.
468 */
Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4 * args,JValue * pResult)469 static void Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4* args,
470 JValue* pResult)
471 {
472 int flags = args[0];
473
474 dvmDumpAllClasses(flags);
475
476 RETURN_VOID();
477 }
478
479 /*
480 * static int getLoadedClassCount()
481 *
482 * Return the number of loaded classes
483 */
Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4 * args,JValue * pResult)484 static void Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4* args,
485 JValue* pResult)
486 {
487 int count;
488
489 UNUSED_PARAMETER(args);
490
491 count = dvmGetNumLoadedClasses();
492
493 RETURN_INT(count);
494 }
495
496 /*
497 * Returns the thread-specific CPU-time clock value for the current thread,
498 * or -1 if the feature isn't supported.
499 */
Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4 * args,JValue * pResult)500 static void Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4* args,
501 JValue* pResult)
502 {
503 jlong result;
504
505 #ifdef HAVE_POSIX_CLOCKS
506 struct timespec now;
507 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
508 result = (jlong) (now.tv_sec*1000000000LL + now.tv_nsec);
509 #else
510 result = (jlong) -1;
511 #endif
512
513 RETURN_LONG(result);
514 }
515
516 /*
517 * static void dumpHprofData(String fileName, FileDescriptor fd)
518 *
519 * Cause "hprof" data to be dumped. We can throw an IOException if an
520 * error occurs during file handling.
521 */
Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4 * args,JValue * pResult)522 static void Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4* args,
523 JValue* pResult)
524 {
525 StringObject* fileNameStr = (StringObject*) args[0];
526 Object* fileDescriptor = (Object*) args[1];
527 char* fileName;
528 int result;
529
530 /*
531 * Only one of these may be NULL.
532 */
533 if (fileNameStr == NULL && fileDescriptor == NULL) {
534 dvmThrowNullPointerException("fileName == null && fd == null");
535 RETURN_VOID();
536 }
537
538 if (fileNameStr != NULL) {
539 fileName = dvmCreateCstrFromString(fileNameStr);
540 if (fileName == NULL) {
541 /* unexpected -- malloc failure? */
542 dvmThrowRuntimeException("malloc failure?");
543 RETURN_VOID();
544 }
545 } else {
546 fileName = strdup("[fd]");
547 }
548
549 int fd = -1;
550 if (fileDescriptor != NULL) {
551 fd = getFileDescriptor(fileDescriptor);
552 if (fd < 0) {
553 free(fileName);
554 RETURN_VOID();
555 }
556 }
557
558 result = hprofDumpHeap(fileName, fd, false);
559 free(fileName);
560
561 if (result != 0) {
562 /* ideally we'd throw something more specific based on actual failure */
563 dvmThrowRuntimeException(
564 "Failure during heap dump; check log output for details");
565 RETURN_VOID();
566 }
567
568 RETURN_VOID();
569 }
570
571 /*
572 * static void dumpHprofDataDdms()
573 *
574 * Cause "hprof" data to be computed and sent directly to DDMS.
575 */
Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4 * args,JValue * pResult)576 static void Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4* args,
577 JValue* pResult)
578 {
579 int result;
580
581 result = hprofDumpHeap("[DDMS]", -1, true);
582
583 if (result != 0) {
584 /* ideally we'd throw something more specific based on actual failure */
585 dvmThrowRuntimeException(
586 "Failure during heap dump; check log output for details");
587 RETURN_VOID();
588 }
589
590 RETURN_VOID();
591 }
592
593 /*
594 * static boolean cacheRegisterMap(String classAndMethodDescr)
595 *
596 * If the specified class is loaded, and the named method exists, ensure
597 * that the method's register map is ready for use. If the class/method
598 * cannot be found, nothing happens.
599 *
600 * This can improve the zygote's sharing of compressed register maps. Do
601 * this after class preloading.
602 *
603 * Returns true if the register map is cached and ready, either as a result
604 * of this call or earlier activity. Returns false if the class isn't loaded,
605 * if the method couldn't be found, or if the method has no register map.
606 *
607 * (Uncomment logs in dvmGetExpandedRegisterMap0() to gather stats.)
608 */
Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4 * args,JValue * pResult)609 static void Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4* args,
610 JValue* pResult)
611 {
612 StringObject* classAndMethodDescStr = (StringObject*) args[0];
613 ClassObject* clazz;
614 bool result = false;
615
616 if (classAndMethodDescStr == NULL) {
617 dvmThrowNullPointerException("classAndMethodDesc == null");
618 RETURN_VOID();
619 }
620
621 char* classAndMethodDesc = NULL;
622
623 /*
624 * Pick the string apart. We have a local copy, so just modify it
625 * in place.
626 */
627 classAndMethodDesc = dvmCreateCstrFromString(classAndMethodDescStr);
628
629 char* methodName = strchr(classAndMethodDesc, '.');
630 if (methodName == NULL) {
631 dvmThrowRuntimeException("method name not found in string");
632 RETURN_VOID();
633 }
634 *methodName++ = '\0';
635
636 char* methodDescr = strchr(methodName, ':');
637 if (methodDescr == NULL) {
638 dvmThrowRuntimeException("method descriptor not found in string");
639 RETURN_VOID();
640 }
641 *methodDescr++ = '\0';
642
643 //ALOGD("GOT: %s %s %s", classAndMethodDesc, methodName, methodDescr);
644
645 /*
646 * Find the class, but only if it's already loaded.
647 */
648 clazz = dvmLookupClass(classAndMethodDesc, NULL, false);
649 if (clazz == NULL) {
650 ALOGD("Class %s not found in bootstrap loader", classAndMethodDesc);
651 goto bail;
652 }
653
654 Method* method;
655
656 /*
657 * Find the method, which could be virtual or direct, defined directly
658 * or inherited.
659 */
660 if (methodName[0] == '<') {
661 /*
662 * Constructor or class initializer. Only need to examine the
663 * "direct" list, and don't need to search up the class hierarchy.
664 */
665 method = dvmFindDirectMethodByDescriptor(clazz, methodName,
666 methodDescr);
667 } else {
668 /*
669 * Try both lists, and scan up the tree.
670 */
671 method = dvmFindVirtualMethodHierByDescriptor(clazz, methodName,
672 methodDescr);
673 if (method == NULL) {
674 method = dvmFindDirectMethodHierByDescriptor(clazz, methodName,
675 methodDescr);
676 }
677 }
678
679 if (method != NULL) {
680 /*
681 * Got it. See if there's a register map here.
682 */
683 const RegisterMap* pMap;
684 pMap = dvmGetExpandedRegisterMap(method);
685 if (pMap == NULL) {
686 ALOGV("No map for %s.%s %s",
687 classAndMethodDesc, methodName, methodDescr);
688 } else {
689 ALOGV("Found map %s.%s %s",
690 classAndMethodDesc, methodName, methodDescr);
691 result = true;
692 }
693 } else {
694 ALOGV("Unable to find %s.%s %s",
695 classAndMethodDesc, methodName, methodDescr);
696 }
697
698 bail:
699 free(classAndMethodDesc);
700 RETURN_BOOLEAN(result);
701 }
702
703 /*
704 * static void dumpReferenceTables()
705 */
Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4 * args,JValue * pResult)706 static void Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4* args,
707 JValue* pResult)
708 {
709 UNUSED_PARAMETER(args);
710 UNUSED_PARAMETER(pResult);
711
712 ALOGI("--- reference table dump ---");
713 dvmDumpJniReferenceTables();
714 // could dump thread's internalLocalRefTable, probably not useful
715 // ditto for thread's jniMonitorRefTable
716 ALOGI("---");
717 RETURN_VOID();
718 }
719
720 /*
721 * static void crash()
722 *
723 * Dump the current thread's interpreted stack and abort the VM. Useful
724 * for seeing both interpreted and native stack traces.
725 *
726 * (Might want to restrict this to debuggable processes as a security
727 * measure, or check SecurityManager.checkExit().)
728 */
Dalvik_dalvik_system_VMDebug_crash(const u4 * args,JValue * pResult)729 static void Dalvik_dalvik_system_VMDebug_crash(const u4* args,
730 JValue* pResult)
731 {
732 UNUSED_PARAMETER(args);
733 UNUSED_PARAMETER(pResult);
734
735 ALOGW("Crashing VM on request");
736 dvmDumpThread(dvmThreadSelf(), false);
737 dvmAbort();
738 }
739
740 /*
741 * static void infopoint(int id)
742 *
743 * Provide a hook for gdb to hang to so that the VM can be stopped when
744 * user-tagged source locations are being executed.
745 */
Dalvik_dalvik_system_VMDebug_infopoint(const u4 * args,JValue * pResult)746 static void Dalvik_dalvik_system_VMDebug_infopoint(const u4* args,
747 JValue* pResult)
748 {
749 gDvm.nativeDebuggerActive = true;
750
751 ALOGD("VMDebug infopoint %d hit", args[0]);
752
753 gDvm.nativeDebuggerActive = false;
754 RETURN_VOID();
755 }
756
Dalvik_dalvik_system_VMDebug_countInstancesOfClass(const u4 * args,JValue * pResult)757 static void Dalvik_dalvik_system_VMDebug_countInstancesOfClass(const u4* args,
758 JValue* pResult)
759 {
760 ClassObject* clazz = (ClassObject*)args[0];
761 bool countAssignable = args[1];
762 if (clazz == NULL) {
763 RETURN_LONG(0);
764 }
765 if (countAssignable) {
766 size_t count = dvmCountAssignableInstancesOfClass(clazz);
767 RETURN_LONG((long long)count);
768 } else {
769 size_t count = dvmCountInstancesOfClass(clazz);
770 RETURN_LONG((long long)count);
771 }
772 }
773
774 /*
775 * public static native void getHeapSpaceStats(long[] data)
776 */
Dalvik_dalvik_system_VMDebug_getHeapSpaceStats(const u4 * args,JValue * pResult)777 static void Dalvik_dalvik_system_VMDebug_getHeapSpaceStats(const u4* args,
778 JValue* pResult)
779 {
780 ArrayObject* dataArray = (ArrayObject*) args[0];
781
782 if (dataArray == NULL || dataArray->length < 6) {
783 RETURN_VOID();
784 }
785
786 jlong* arr = (jlong*)(void*)dataArray->contents;
787
788 int j = 0;
789 size_t per_heap_allocated[2];
790 size_t per_heap_size[2];
791 memset(per_heap_allocated, 0, sizeof(per_heap_allocated));
792 memset(per_heap_size, 0, sizeof(per_heap_size));
793 dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, (size_t*) &per_heap_allocated, 2);
794 dvmHeapSourceGetValue(HS_FOOTPRINT, (size_t*) &per_heap_size, 2);
795 jlong heapSize = per_heap_size[0];
796 jlong heapUsed = per_heap_allocated[0];
797 jlong heapFree = heapSize - heapUsed;
798 jlong zygoteSize = per_heap_size[1];
799 jlong zygoteUsed = per_heap_allocated[1];
800 jlong zygoteFree = zygoteSize - zygoteUsed;
801 arr[j++] = heapSize;
802 arr[j++] = heapUsed;
803 arr[j++] = heapFree;
804 arr[j++] = zygoteSize;
805 arr[j++] = zygoteUsed;
806 arr[j++] = zygoteFree;
807
808 RETURN_VOID();
809 }
810
811 const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = {
812 { "getVmFeatureList", "()[Ljava/lang/String;",
813 Dalvik_dalvik_system_VMDebug_getVmFeatureList },
814 { "getAllocCount", "(I)I",
815 Dalvik_dalvik_system_VMDebug_getAllocCount },
816 { "getHeapSpaceStats", "([J)V",
817 Dalvik_dalvik_system_VMDebug_getHeapSpaceStats },
818 { "resetAllocCount", "(I)V",
819 Dalvik_dalvik_system_VMDebug_resetAllocCount },
820 { "startAllocCounting", "()V",
821 Dalvik_dalvik_system_VMDebug_startAllocCounting },
822 { "stopAllocCounting", "()V",
823 Dalvik_dalvik_system_VMDebug_stopAllocCounting },
824 { "startMethodTracingDdmsImpl", "(IIZI)V",
825 Dalvik_dalvik_system_VMDebug_startMethodTracingDdmsImpl },
826 { "startMethodTracingFd", "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V",
827 Dalvik_dalvik_system_VMDebug_startMethodTracingFd },
828 { "startMethodTracingFilename", "(Ljava/lang/String;II)V",
829 Dalvik_dalvik_system_VMDebug_startMethodTracingFilename },
830 { "getMethodTracingMode", "()I",
831 Dalvik_dalvik_system_VMDebug_getMethodTracingMode },
832 { "stopMethodTracing", "()V",
833 Dalvik_dalvik_system_VMDebug_stopMethodTracing },
834 { "startEmulatorTracing", "()V",
835 Dalvik_dalvik_system_VMDebug_startEmulatorTracing },
836 { "stopEmulatorTracing", "()V",
837 Dalvik_dalvik_system_VMDebug_stopEmulatorTracing },
838 { "startInstructionCounting", "()V",
839 Dalvik_dalvik_system_VMDebug_startInstructionCounting },
840 { "stopInstructionCounting", "()V",
841 Dalvik_dalvik_system_VMDebug_stopInstructionCounting },
842 { "resetInstructionCount", "()V",
843 Dalvik_dalvik_system_VMDebug_resetInstructionCount },
844 { "getInstructionCount", "([I)V",
845 Dalvik_dalvik_system_VMDebug_getInstructionCount },
846 { "isDebuggerConnected", "()Z",
847 Dalvik_dalvik_system_VMDebug_isDebuggerConnected },
848 { "isDebuggingEnabled", "()Z",
849 Dalvik_dalvik_system_VMDebug_isDebuggingEnabled },
850 { "lastDebuggerActivity", "()J",
851 Dalvik_dalvik_system_VMDebug_lastDebuggerActivity },
852 { "printLoadedClasses", "(I)V",
853 Dalvik_dalvik_system_VMDebug_printLoadedClasses },
854 { "getLoadedClassCount", "()I",
855 Dalvik_dalvik_system_VMDebug_getLoadedClassCount },
856 { "threadCpuTimeNanos", "()J",
857 Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
858 { "dumpHprofData", "(Ljava/lang/String;Ljava/io/FileDescriptor;)V",
859 Dalvik_dalvik_system_VMDebug_dumpHprofData },
860 { "dumpHprofDataDdms", "()V",
861 Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms },
862 { "cacheRegisterMap", "(Ljava/lang/String;)Z",
863 Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
864 { "dumpReferenceTables", "()V",
865 Dalvik_dalvik_system_VMDebug_dumpReferenceTables },
866 { "crash", "()V",
867 Dalvik_dalvik_system_VMDebug_crash },
868 { "infopoint", "(I)V",
869 Dalvik_dalvik_system_VMDebug_infopoint },
870 { "countInstancesOfClass", "(Ljava/lang/Class;Z)J",
871 Dalvik_dalvik_system_VMDebug_countInstancesOfClass },
872 { NULL, NULL, NULL },
873 };
874