blob: 612c9b51cc7c9848f746f062cc01876877d42edb [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
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 "native/InternalNativePriv.h"
22
Andy McFadden01718122010-01-22 16:36:30 -080023#include <errno.h>
24
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080025
Andy McFaddenfd52c652010-01-22 07:23:40 -080026/*
27 * Convert an array of char* into a String[].
28 *
29 * Returns NULL on failure, with an exception raised.
30 */
31static ArrayObject* convertStringArray(char** strings, size_t count)
32{
33 /*
34 * Allocate an array to hold the String objects.
35 */
36 ClassObject* stringArrayClass =
37 dvmFindArrayClass("[Ljava/lang/String;", NULL);
38 if (stringArrayClass == NULL) {
39 /* shouldn't happen */
40 LOGE("Unable to find [Ljava/lang/String;\n");
41 dvmAbort();
42 }
43
44 ArrayObject* stringArray =
45 dvmAllocArrayByClass(stringArrayClass, count, ALLOC_DEFAULT);
46 if (stringArray == NULL) {
47 /* probably OOM */
48 LOGD("Failed allocating array of %d strings\n", count);
49 return NULL;
50 }
51
52 /*
53 * Create the individual String objects and add them to the array.
54 *
55 * We can use ALLOC_DONT_TRACK here because the objects are being
56 * added to a tracked array object as they're created.
57 */
58 StringObject** contents = (StringObject**) stringArray->contents;
59 size_t i;
60 for (i = 0; i < count; i++) {
61 contents[i] = dvmCreateStringFromCstr(strings[i], ALLOC_DONT_TRACK);
62 if (contents[i] == NULL) {
63 /* probably OOM; drop out now */
64 assert(dvmCheckException(dvmThreadSelf()));
65 dvmReleaseTrackedAlloc((Object*)stringArray, NULL);
66 return NULL;
67 }
68 }
69
70 dvmReleaseTrackedAlloc((Object*)stringArray, NULL);
71 return stringArray;
72}
73
74/*
75 * static String[] getVmFeatureList()
76 *
77 * Return a set of strings describing available VM features (this is chiefly
78 * of interest to DDMS). Some features may be controlled by compile-time
79 * or command-line flags.
80 */
81static void Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4* args,
82 JValue* pResult)
83{
84 static const int MAX_FEATURE_COUNT = 10;
85 char* features[MAX_FEATURE_COUNT];
86 int idx = 0;
87
88#ifdef WITH_PROFILER
89 /* VM responds to DDMS method profiling requests */
90 features[idx++] = "method-trace-profiling";
Andy McFadden01718122010-01-22 16:36:30 -080091 features[idx++] = "method-trace-profiling-streaming";
Andy McFaddenfd52c652010-01-22 07:23:40 -080092#endif
93#ifdef WITH_HPROF
94 /* VM responds to DDMS heap dump requests */
95 features[idx++] = "hprof-heap-dump";
Andy McFadden6bf992c2010-01-28 17:01:39 -080096 features[idx++] = "hprof-heap-dump-streaming";
Andy McFaddenfd52c652010-01-22 07:23:40 -080097#endif
98
99 assert(idx <= MAX_FEATURE_COUNT);
100
101 LOGV("+++ sending up %d features\n", idx);
102 ArrayObject* arrayObj = convertStringArray(features, idx);
103 RETURN_PTR(arrayObj); /* will be null on OOM */
104}
105
106
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800107#ifdef WITH_PROFILER
108/* These must match the values in dalvik.system.VMDebug.
109 */
110enum {
Andy McFaddene15a8eb2010-02-22 17:07:23 -0800111 KIND_ALLOCATED_OBJECTS = 1<<0,
112 KIND_ALLOCATED_BYTES = 1<<1,
113 KIND_FREED_OBJECTS = 1<<2,
114 KIND_FREED_BYTES = 1<<3,
115 KIND_GC_INVOCATIONS = 1<<4,
116 KIND_CLASS_INIT_COUNT = 1<<5,
117 KIND_CLASS_INIT_TIME = 1<<6,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800118#if PROFILE_EXTERNAL_ALLOCATIONS
119 KIND_EXT_ALLOCATED_OBJECTS = 1<<12,
120 KIND_EXT_ALLOCATED_BYTES = 1<<13,
121 KIND_EXT_FREED_OBJECTS = 1<<14,
122 KIND_EXT_FREED_BYTES = 1<<15,
123#endif // PROFILE_EXTERNAL_ALLOCATIONS
124
125 KIND_GLOBAL_ALLOCATED_OBJECTS = KIND_ALLOCATED_OBJECTS,
126 KIND_GLOBAL_ALLOCATED_BYTES = KIND_ALLOCATED_BYTES,
127 KIND_GLOBAL_FREED_OBJECTS = KIND_FREED_OBJECTS,
128 KIND_GLOBAL_FREED_BYTES = KIND_FREED_BYTES,
129 KIND_GLOBAL_GC_INVOCATIONS = KIND_GC_INVOCATIONS,
Andy McFaddene15a8eb2010-02-22 17:07:23 -0800130 KIND_GLOBAL_CLASS_INIT_COUNT = KIND_CLASS_INIT_COUNT,
131 KIND_GLOBAL_CLASS_INIT_TIME = KIND_CLASS_INIT_TIME,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800132#if PROFILE_EXTERNAL_ALLOCATIONS
133 KIND_GLOBAL_EXT_ALLOCATED_OBJECTS = KIND_EXT_ALLOCATED_OBJECTS,
134 KIND_GLOBAL_EXT_ALLOCATED_BYTES = KIND_EXT_ALLOCATED_BYTES,
135 KIND_GLOBAL_EXT_FREED_OBJECTS = KIND_EXT_FREED_OBJECTS,
136 KIND_GLOBAL_EXT_FREED_BYTES = KIND_EXT_FREED_BYTES,
137#endif // PROFILE_EXTERNAL_ALLOCATIONS
138
139 KIND_THREAD_ALLOCATED_OBJECTS = KIND_ALLOCATED_OBJECTS << 16,
140 KIND_THREAD_ALLOCATED_BYTES = KIND_ALLOCATED_BYTES << 16,
141 KIND_THREAD_FREED_OBJECTS = KIND_FREED_OBJECTS << 16,
142 KIND_THREAD_FREED_BYTES = KIND_FREED_BYTES << 16,
143#if PROFILE_EXTERNAL_ALLOCATIONS
144 KIND_THREAD_EXT_ALLOCATED_OBJECTS = KIND_EXT_ALLOCATED_OBJECTS << 16,
145 KIND_THREAD_EXT_ALLOCATED_BYTES = KIND_EXT_ALLOCATED_BYTES << 16,
146 KIND_THREAD_EXT_FREED_OBJECTS = KIND_EXT_FREED_OBJECTS << 16,
147 KIND_THREAD_EXT_FREED_BYTES = KIND_EXT_FREED_BYTES << 16,
148#endif // PROFILE_EXTERNAL_ALLOCATIONS
149 KIND_THREAD_GC_INVOCATIONS = KIND_GC_INVOCATIONS << 16,
150
151 // TODO: failedAllocCount, failedAllocSize
152};
153
154#define KIND_ALL_COUNTS 0xffffffff
155
156/*
157 * Zero out the specified fields.
158 */
159static void clearAllocProfStateFields(AllocProfState *allocProf,
160 unsigned int kinds)
161{
162 if (kinds & KIND_ALLOCATED_OBJECTS) {
163 allocProf->allocCount = 0;
164 }
165 if (kinds & KIND_ALLOCATED_BYTES) {
166 allocProf->allocSize = 0;
167 }
168 if (kinds & KIND_FREED_OBJECTS) {
169 allocProf->freeCount = 0;
170 }
171 if (kinds & KIND_FREED_BYTES) {
172 allocProf->freeSize = 0;
173 }
174 if (kinds & KIND_GC_INVOCATIONS) {
175 allocProf->gcCount = 0;
176 }
Andy McFaddene15a8eb2010-02-22 17:07:23 -0800177 if (kinds & KIND_CLASS_INIT_COUNT) {
178 allocProf->classInitCount = 0;
179 }
180 if (kinds & KIND_CLASS_INIT_TIME) {
181 allocProf->classInitTime = 0;
182 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800183#if PROFILE_EXTERNAL_ALLOCATIONS
184 if (kinds & KIND_EXT_ALLOCATED_OBJECTS) {
185 allocProf->externalAllocCount = 0;
186 }
187 if (kinds & KIND_EXT_ALLOCATED_BYTES) {
188 allocProf->externalAllocSize = 0;
189 }
190 if (kinds & KIND_EXT_FREED_OBJECTS) {
191 allocProf->externalFreeCount = 0;
192 }
193 if (kinds & KIND_EXT_FREED_BYTES) {
194 allocProf->externalFreeSize = 0;
195 }
196#endif // PROFILE_EXTERNAL_ALLOCATIONS
197}
198#endif
199
200/*
201 * static void startAllocCounting()
202 *
203 * Reset the counters and enable counting.
204 *
205 * TODO: this currently only resets the per-thread counters for the current
206 * thread. If we actually start using the per-thread counters we'll
207 * probably want to fix this.
208 */
209static void Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4* args,
210 JValue* pResult)
211{
212 UNUSED_PARAMETER(args);
213
214#ifdef WITH_PROFILER
215 clearAllocProfStateFields(&gDvm.allocProf, KIND_ALL_COUNTS);
216 clearAllocProfStateFields(&dvmThreadSelf()->allocProf, KIND_ALL_COUNTS);
217 dvmStartAllocCounting();
218#endif
219 RETURN_VOID();
220}
221
222/*
223 * public static void stopAllocCounting()
224 */
225static void Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4* args,
226 JValue* pResult)
227{
228 UNUSED_PARAMETER(args);
229
230#ifdef WITH_PROFILER
231 dvmStopAllocCounting();
232#endif
233 RETURN_VOID();
234}
235
236/*
237 * private static int getAllocCount(int kind)
238 */
239static void Dalvik_dalvik_system_VMDebug_getAllocCount(const u4* args,
240 JValue* pResult)
241{
242#ifdef WITH_PROFILER
243 AllocProfState *allocProf;
244 unsigned int kind = args[0];
245 if (kind < (1<<16)) {
246 allocProf = &gDvm.allocProf;
247 } else {
248 allocProf = &dvmThreadSelf()->allocProf;
249 kind >>= 16;
250 }
251 switch (kind) {
252 case KIND_ALLOCATED_OBJECTS:
253 pResult->i = allocProf->allocCount;
254 break;
255 case KIND_ALLOCATED_BYTES:
256 pResult->i = allocProf->allocSize;
257 break;
258 case KIND_FREED_OBJECTS:
259 pResult->i = allocProf->freeCount;
260 break;
261 case KIND_FREED_BYTES:
262 pResult->i = allocProf->freeSize;
263 break;
264 case KIND_GC_INVOCATIONS:
265 pResult->i = allocProf->gcCount;
266 break;
Andy McFaddene15a8eb2010-02-22 17:07:23 -0800267 case KIND_CLASS_INIT_COUNT:
268 pResult->i = allocProf->classInitCount;
269 break;
270 case KIND_CLASS_INIT_TIME:
271 /* convert nsec to usec, reduce to 32 bits */
272 pResult->i = (int) (allocProf->classInitTime / 1000);
273 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800274#if PROFILE_EXTERNAL_ALLOCATIONS
275 case KIND_EXT_ALLOCATED_OBJECTS:
276 pResult->i = allocProf->externalAllocCount;
277 break;
278 case KIND_EXT_ALLOCATED_BYTES:
279 pResult->i = allocProf->externalAllocSize;
280 break;
281 case KIND_EXT_FREED_OBJECTS:
282 pResult->i = allocProf->externalFreeCount;
283 break;
284 case KIND_EXT_FREED_BYTES:
285 pResult->i = allocProf->externalFreeSize;
286 break;
287#endif // PROFILE_EXTERNAL_ALLOCATIONS
288 default:
289 assert(false);
290 pResult->i = -1;
291 }
292#else
293 RETURN_INT(-1);
294#endif
295}
296
297/*
298 * public static void resetAllocCount(int kinds)
299 */
300static void Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4* args,
301 JValue* pResult)
302{
303#ifdef WITH_PROFILER
304 unsigned int kinds = args[0];
305 clearAllocProfStateFields(&gDvm.allocProf, kinds & 0xffff);
306 clearAllocProfStateFields(&dvmThreadSelf()->allocProf, kinds >> 16);
307#endif
308 RETURN_VOID();
309}
310
311/*
Andy McFadden01718122010-01-22 16:36:30 -0800312 * static void startMethodTracingNative(String traceFileName,
313 * FileDescriptor fd, int bufferSize, int flags)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800314 *
315 * Start method trace profiling.
Andy McFadden01718122010-01-22 16:36:30 -0800316 *
317 * If both "traceFileName" and "fd" are null, the result will be sent
318 * directly to DDMS. (The non-DDMS versions of the calls are expected
319 * to enforce non-NULL filenames.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800320 */
Andy McFadden01718122010-01-22 16:36:30 -0800321static void Dalvik_dalvik_system_VMDebug_startMethodTracingNative(const u4* args,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800322 JValue* pResult)
323{
324#ifdef WITH_PROFILER
325 StringObject* traceFileStr = (StringObject*) args[0];
Dianne Hackborn0f0ae022009-06-23 19:21:10 -0700326 DataObject* traceFd = (DataObject*) args[1];
327 int bufferSize = args[2];
328 int flags = args[3];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800329
330 if (bufferSize == 0) {
331 // Default to 8MB per the documentation.
332 bufferSize = 8 * 1024 * 1024;
333 }
334
Andy McFadden01718122010-01-22 16:36:30 -0800335 if (bufferSize < 1024) {
Dianne Hackborn0f0ae022009-06-23 19:21:10 -0700336 dvmThrowException("Ljava/lang/IllegalArgumentException;", NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800337 RETURN_VOID();
338 }
339
Andy McFadden01718122010-01-22 16:36:30 -0800340 char* traceFileName = NULL;
341 if (traceFileStr != NULL)
342 traceFileName = dvmCreateCstrFromString(traceFileStr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800343
Dianne Hackborn0f0ae022009-06-23 19:21:10 -0700344 int fd = -1;
345 if (traceFd != NULL) {
Andy McFadden01718122010-01-22 16:36:30 -0800346 InstField* field =
347 dvmFindInstanceField(traceFd->obj.clazz, "descriptor", "I");
Dianne Hackborn0f0ae022009-06-23 19:21:10 -0700348 if (field == NULL) {
349 dvmThrowException("Ljava/lang/NoSuchFieldException;",
350 "No FileDescriptor.descriptor field");
351 RETURN_VOID();
352 }
353 fd = dup(dvmGetFieldInt(&traceFd->obj, field->byteOffset));
Andy McFadden01718122010-01-22 16:36:30 -0800354 if (fd < 0) {
355 dvmThrowExceptionFmt("Ljava/lang/RuntimeException;",
356 "dup() failed: %s", strerror(errno));
357 RETURN_VOID();
358 }
Dianne Hackborn0f0ae022009-06-23 19:21:10 -0700359 }
360
Andy McFadden01718122010-01-22 16:36:30 -0800361 dvmMethodTraceStart(traceFileName != NULL ? traceFileName : "[DDMS]",
362 fd, bufferSize, flags, (traceFileName == NULL && fd == -1));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800363 free(traceFileName);
364#else
365 // throw exception?
366#endif
367 RETURN_VOID();
368}
369
370/*
The Android Open Source Project99409882009-03-18 22:20:24 -0700371 * static boolean isMethodTracingActive()
372 *
373 * Determine whether method tracing is currently active.
374 */
375static void Dalvik_dalvik_system_VMDebug_isMethodTracingActive(const u4* args,
376 JValue* pResult)
377{
378 UNUSED_PARAMETER(args);
379
380#ifdef WITH_PROFILER
381 RETURN_BOOLEAN(dvmIsMethodTraceActive());
382#else
383 RETURN_BOOLEAN(false);
384#endif
385}
386
387/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800388 * static void stopMethodTracing()
389 *
390 * Stop method tracing.
391 */
392static void Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4* args,
393 JValue* pResult)
394{
395 UNUSED_PARAMETER(args);
396
397#ifdef WITH_PROFILER
398 dvmMethodTraceStop();
399#else
400 // throw exception?
401#endif
402 RETURN_VOID();
403}
404
405/*
406 * static void startEmulatorTracing()
407 *
408 * Start sending method trace info to the emulator.
409 */
410static void Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4* args,
411 JValue* pResult)
412{
413 UNUSED_PARAMETER(args);
414
415#ifdef WITH_PROFILER
416 dvmEmulatorTraceStart();
417#else
418 // throw exception?
419#endif
420 RETURN_VOID();
421}
422
423/*
424 * static void stopEmulatorTracing()
425 *
426 * Start sending method trace info to the emulator.
427 */
428static void Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4* args,
429 JValue* pResult)
430{
431 UNUSED_PARAMETER(args);
432
433#ifdef WITH_PROFILER
434 dvmEmulatorTraceStop();
435#else
436 // throw exception?
437#endif
438 RETURN_VOID();
439}
440
441/*
442 * static int setAllocationLimit(int limit)
443 *
444 * Set the current allocation limit in this thread. Return the previous
445 * value.
446 */
447static void Dalvik_dalvik_system_VMDebug_setAllocationLimit(const u4* args,
448 JValue* pResult)
449{
450#if defined(WITH_ALLOC_LIMITS)
451 gDvm.checkAllocLimits = true;
452
453 Thread* self = dvmThreadSelf();
454 int newLimit = args[0];
455 int oldLimit = self->allocLimit;
456
457 if (newLimit < -1) {
458 LOGE("WARNING: bad limit request (%d)\n", newLimit);
459 newLimit = -1;
460 }
461 self->allocLimit = newLimit;
462 RETURN_INT(oldLimit);
463#else
464 UNUSED_PARAMETER(args);
465 RETURN_INT(-1);
466#endif
467}
468
469/*
470 * static int setGlobalAllocationLimit(int limit)
471 *
472 * Set the allocation limit for this process. Returns the previous value.
473 */
474static void Dalvik_dalvik_system_VMDebug_setGlobalAllocationLimit(const u4* args,
475 JValue* pResult)
476{
477#if defined(WITH_ALLOC_LIMITS)
478 gDvm.checkAllocLimits = true;
479
480 int newLimit = args[0];
481 int oldLimit = gDvm.allocationLimit;
482
483 if (newLimit < -1 || newLimit > 0) {
484 LOGE("WARNING: bad limit request (%d)\n", newLimit);
485 newLimit = -1;
486 }
487 // TODO: should use an atomic swap here
488 gDvm.allocationLimit = newLimit;
489 RETURN_INT(oldLimit);
490#else
491 UNUSED_PARAMETER(args);
492 RETURN_INT(-1);
493#endif
494}
495
496/*
497 * static boolean isDebuggerConnected()
498 *
499 * Returns "true" if a debugger is attached.
500 */
501static void Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4* args,
502 JValue* pResult)
503{
504 UNUSED_PARAMETER(args);
505
506 RETURN_BOOLEAN(dvmDbgIsDebuggerConnected());
507}
508
509/*
510 * static boolean isDebuggingEnabled()
511 *
512 * Returns "true" if debugging is enabled.
513 */
514static void Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4* args,
515 JValue* pResult)
516{
517 UNUSED_PARAMETER(args);
518
519 RETURN_BOOLEAN(gDvm.jdwpConfigured);
520}
521
522/*
523 * static long lastDebuggerActivity()
524 *
525 * Returns the time, in msec, since we last had an interaction with the
526 * debugger (send or receive).
527 */
528static void Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4* args,
529 JValue* pResult)
530{
531 UNUSED_PARAMETER(args);
532
533 RETURN_LONG(dvmDbgLastDebuggerActivity());
534}
535
536/*
537 * static void startInstructionCounting()
538 */
539static void Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4* args,
540 JValue* pResult)
541{
542#if defined(WITH_PROFILER)
543 dvmStartInstructionCounting();
544#else
545 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
546#endif
547 RETURN_VOID();
548}
549
550/*
551 * static void stopInstructionCounting()
552 */
553static void Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4* args,
554 JValue* pResult)
555{
556#if defined(WITH_PROFILER)
557 dvmStopInstructionCounting();
558#else
559 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
560#endif
561 RETURN_VOID();
562}
563
564/*
565 * static boolean getInstructionCount(int[] counts)
566 *
567 * Grab a copy of the global instruction count array.
568 *
569 * Since the instruction counts aren't synchronized, we use sched_yield
570 * to improve our chances of finishing without contention. (Only makes
571 * sense on a uniprocessor.)
572 */
573static void Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4* args,
574 JValue* pResult)
575{
576#if defined(WITH_PROFILER)
577 ArrayObject* countArray = (ArrayObject*) args[0];
578 int* storage;
579
580 storage = (int*) countArray->contents;
581 sched_yield();
582 memcpy(storage, gDvm.executedInstrCounts,
583 kNumDalvikInstructions * sizeof(int));
584#else
585 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
586#endif
587 RETURN_VOID();
588}
589
590/*
591 * static boolean resetInstructionCount()
592 *
593 * Reset the instruction count array.
594 */
595static void Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4* args,
596 JValue* pResult)
597{
598#if defined(WITH_PROFILER)
599 sched_yield();
600 memset(gDvm.executedInstrCounts, 0, kNumDalvikInstructions * sizeof(int));
601#else
602 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
603#endif
604 RETURN_VOID();
605}
606
607/*
608 * static void printLoadedClasses(int flags)
609 *
610 * Dump the list of loaded classes.
611 */
612static void Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4* args,
613 JValue* pResult)
614{
615 int flags = args[0];
616
617 dvmDumpAllClasses(flags);
618
619 RETURN_VOID();
620}
621
622/*
623 * static int getLoadedClassCount()
624 *
625 * Return the number of loaded classes
626 */
627static void Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4* args,
628 JValue* pResult)
629{
630 int count;
631
632 UNUSED_PARAMETER(args);
633
634 count = dvmGetNumLoadedClasses();
635
636 RETURN_INT(count);
637}
638
639/*
640 * Returns the thread-specific CPU-time clock value for the current thread,
641 * or -1 if the feature isn't supported.
642 */
643static void Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4* args,
644 JValue* pResult)
645{
646 jlong result;
647
648#ifdef HAVE_POSIX_CLOCKS
649 struct timespec now;
650 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
651 result = (jlong) (now.tv_sec*1000000000LL + now.tv_nsec);
652#else
653 result = (jlong) -1;
654#endif
655
656 RETURN_LONG(result);
657}
658
659/*
660 * static void dumpHprofData(String fileName)
661 *
662 * Cause "hprof" data to be dumped. We can throw an IOException if an
663 * error occurs during file handling.
664 */
665static void Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4* args,
666 JValue* pResult)
667{
668#ifdef WITH_HPROF
669 StringObject* fileNameStr = (StringObject*) args[0];
670 char* fileName;
The Android Open Source Project99409882009-03-18 22:20:24 -0700671 int result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800672
673 if (fileNameStr == NULL) {
674 dvmThrowException("Ljava/lang/NullPointerException;", NULL);
675 RETURN_VOID();
676 }
677
678 fileName = dvmCreateCstrFromString(fileNameStr);
679 if (fileName == NULL) {
680 /* unexpected -- malloc failure? */
681 dvmThrowException("Ljava/lang/RuntimeException;", "malloc failure?");
682 RETURN_VOID();
683 }
684
Andy McFadden6bf992c2010-01-28 17:01:39 -0800685 result = hprofDumpHeap(fileName, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800686 free(fileName);
The Android Open Source Project99409882009-03-18 22:20:24 -0700687
688 if (result != 0) {
689 /* ideally we'd throw something more specific based on actual failure */
690 dvmThrowException("Ljava/lang/RuntimeException;",
691 "Failure during heap dump -- check log output for details");
692 RETURN_VOID();
693 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800694#else
695 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
696#endif
697
698 RETURN_VOID();
699}
700
Andy McFadden9faa9e62009-04-08 00:35:55 -0700701/*
Andy McFadden6bf992c2010-01-28 17:01:39 -0800702 * static void dumpHprofDataDdms()
703 *
704 * Cause "hprof" data to be computed and sent directly to DDMS.
705 */
706static void Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4* args,
707 JValue* pResult)
708{
709#ifdef WITH_HPROF
710 int result;
711
712 result = hprofDumpHeap("[DDMS]", true);
713
714 if (result != 0) {
715 /* ideally we'd throw something more specific based on actual failure */
716 dvmThrowException("Ljava/lang/RuntimeException;",
717 "Failure during heap dump -- check log output for details");
718 RETURN_VOID();
719 }
720#else
721 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
722#endif
723
724 RETURN_VOID();
725}
726
727/*
Andy McFadden9faa9e62009-04-08 00:35:55 -0700728 * static boolean cacheRegisterMap(String classAndMethodDescr)
729 *
730 * If the specified class is loaded, and the named method exists, ensure
731 * that the method's register map is ready for use. If the class/method
732 * cannot be found, nothing happens.
733 *
734 * This can improve the zygote's sharing of compressed register maps. Do
735 * this after class preloading.
736 *
737 * Returns true if the register map is cached and ready, either as a result
738 * of this call or earlier activity. Returns false if the class isn't loaded,
739 * if the method couldn't be found, or if the method has no register map.
740 *
741 * (Uncomment logs in dvmGetExpandedRegisterMap0() to gather stats.)
742 */
743static void Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4* args,
744 JValue* pResult)
745{
746 StringObject* classAndMethodDescStr = (StringObject*) args[0];
747 ClassObject* clazz;
748 bool result = false;
749
750 if (classAndMethodDescStr == NULL) {
751 dvmThrowException("Ljava/lang/NullPointerException;", NULL);
752 RETURN_VOID();
753 }
754
755 char* classAndMethodDesc = NULL;
756
757 /*
758 * Pick the string apart. We have a local copy, so just modify it
759 * in place.
760 */
761 classAndMethodDesc = dvmCreateCstrFromString(classAndMethodDescStr);
762
763 char* methodName = strchr(classAndMethodDesc, '.');
764 if (methodName == NULL) {
765 dvmThrowException("Ljava/lang/RuntimeException;",
766 "method name not found in string");
767 RETURN_VOID();
768 }
769 *methodName++ = '\0';
770
771 char* methodDescr = strchr(methodName, ':');
772 if (methodDescr == NULL) {
773 dvmThrowException("Ljava/lang/RuntimeException;",
774 "method descriptor not found in string");
775 RETURN_VOID();
776 }
777 *methodDescr++ = '\0';
778
779 //LOGD("GOT: %s %s %s\n", classAndMethodDesc, methodName, methodDescr);
780
781 /*
782 * Find the class, but only if it's already loaded.
783 */
784 clazz = dvmLookupClass(classAndMethodDesc, NULL, false);
785 if (clazz == NULL) {
786 LOGD("Class %s not found in bootstrap loader\n", classAndMethodDesc);
787 goto bail;
788 }
789
790 Method* method;
791
792 /*
793 * Find the method, which could be virtual or direct, defined directly
794 * or inherited.
795 */
796 if (methodName[0] == '<') {
797 /*
798 * Constructor or class initializer. Only need to examine the
799 * "direct" list, and don't need to search up the class hierarchy.
800 */
801 method = dvmFindDirectMethodByDescriptor(clazz, methodName,
802 methodDescr);
803 } else {
804 /*
805 * Try both lists, and scan up the tree.
806 */
807 method = dvmFindVirtualMethodHierByDescriptor(clazz, methodName,
808 methodDescr);
809 if (method == NULL) {
810 method = dvmFindDirectMethodHierByDescriptor(clazz, methodName,
811 methodDescr);
812 }
813 }
814
815 if (method != NULL) {
816 /*
817 * Got it. See if there's a register map here.
818 */
819 const RegisterMap* pMap;
820 pMap = dvmGetExpandedRegisterMap(method);
821 if (pMap == NULL) {
822 LOGV("No map for %s.%s %s\n",
823 classAndMethodDesc, methodName, methodDescr);
824 } else {
825 LOGV("Found map %s.%s %s\n",
826 classAndMethodDesc, methodName, methodDescr);
827 result = true;
828 }
829 } else {
830 LOGV("Unable to find %s.%s %s\n",
831 classAndMethodDesc, methodName, methodDescr);
832 }
833
834bail:
835 free(classAndMethodDesc);
836 RETURN_BOOLEAN(result);
837}
838
Andy McFaddene9efb8a2009-07-31 13:54:59 -0700839/*
Andy McFadden92fa4762009-10-22 17:24:45 -0700840 * static void dumpReferenceTables()
841 */
842static void Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4* args,
843 JValue* pResult)
844{
845 UNUSED_PARAMETER(args);
846 UNUSED_PARAMETER(pResult);
847
848 LOGI("--- reference table dump ---\n");
849 dvmDumpJniReferenceTables();
850 // could dump thread's internalLocalRefTable, probably not useful
851 // ditto for thread's jniMonitorRefTable
852 LOGI("---\n");
853 RETURN_VOID();
854}
855
856/*
Andy McFaddene9efb8a2009-07-31 13:54:59 -0700857 * static void crash()
858 *
859 * Dump the current thread's interpreted stack and abort the VM. Useful
860 * for seeing both interpreted and native stack traces.
861 *
862 * (Might want to restrict this to debuggable processes as a security
863 * measure, or check SecurityManager.checkExit().)
864 */
865static void Dalvik_dalvik_system_VMDebug_crash(const u4* args,
866 JValue* pResult)
867{
868 UNUSED_PARAMETER(args);
869 UNUSED_PARAMETER(pResult);
870
871 LOGW("Crashing VM on request\n");
872 dvmDumpThread(dvmThreadSelf(), false);
873 dvmAbort();
874}
875
Ben Cheng7d656dd2010-03-12 16:11:49 -0800876/*
877 * static void infopoint(int id)
878 *
879 * Provide a hook for gdb to hang to so that the VM can be stopped when
880 * user-tagged source locations are being executed.
881 */
882static void Dalvik_dalvik_system_VMDebug_infopoint(const u4* args,
883 JValue* pResult)
884{
885 gDvm.nativeDebuggerActive = true;
886
887 LOGD("VMDebug infopoint %d hit", args[0]);
888
889 gDvm.nativeDebuggerActive = false;
890 RETURN_VOID();
891}
892
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800893const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = {
Andy McFaddenfd52c652010-01-22 07:23:40 -0800894 { "getVmFeatureList", "()[Ljava/lang/String;",
895 Dalvik_dalvik_system_VMDebug_getVmFeatureList },
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800896 { "getAllocCount", "(I)I",
897 Dalvik_dalvik_system_VMDebug_getAllocCount },
898 { "resetAllocCount", "(I)V",
899 Dalvik_dalvik_system_VMDebug_resetAllocCount },
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800900 { "startAllocCounting", "()V",
901 Dalvik_dalvik_system_VMDebug_startAllocCounting },
902 { "stopAllocCounting", "()V",
903 Dalvik_dalvik_system_VMDebug_stopAllocCounting },
Andy McFadden01718122010-01-22 16:36:30 -0800904 { "startMethodTracingNative", "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V",
905 Dalvik_dalvik_system_VMDebug_startMethodTracingNative },
The Android Open Source Project99409882009-03-18 22:20:24 -0700906 { "isMethodTracingActive", "()Z",
907 Dalvik_dalvik_system_VMDebug_isMethodTracingActive },
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800908 { "stopMethodTracing", "()V",
909 Dalvik_dalvik_system_VMDebug_stopMethodTracing },
910 { "startEmulatorTracing", "()V",
911 Dalvik_dalvik_system_VMDebug_startEmulatorTracing },
912 { "stopEmulatorTracing", "()V",
913 Dalvik_dalvik_system_VMDebug_stopEmulatorTracing },
914 { "setAllocationLimit", "(I)I",
915 Dalvik_dalvik_system_VMDebug_setAllocationLimit },
916 { "setGlobalAllocationLimit", "(I)I",
917 Dalvik_dalvik_system_VMDebug_setGlobalAllocationLimit },
918 { "startInstructionCounting", "()V",
919 Dalvik_dalvik_system_VMDebug_startInstructionCounting },
920 { "stopInstructionCounting", "()V",
921 Dalvik_dalvik_system_VMDebug_stopInstructionCounting },
922 { "resetInstructionCount", "()V",
923 Dalvik_dalvik_system_VMDebug_resetInstructionCount },
924 { "getInstructionCount", "([I)V",
925 Dalvik_dalvik_system_VMDebug_getInstructionCount },
926 { "isDebuggerConnected", "()Z",
927 Dalvik_dalvik_system_VMDebug_isDebuggerConnected },
928 { "isDebuggingEnabled", "()Z",
929 Dalvik_dalvik_system_VMDebug_isDebuggingEnabled },
930 { "lastDebuggerActivity", "()J",
931 Dalvik_dalvik_system_VMDebug_lastDebuggerActivity },
932 { "printLoadedClasses", "(I)V",
933 Dalvik_dalvik_system_VMDebug_printLoadedClasses },
934 { "getLoadedClassCount", "()I",
935 Dalvik_dalvik_system_VMDebug_getLoadedClassCount },
936 { "threadCpuTimeNanos", "()J",
937 Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
938 { "dumpHprofData", "(Ljava/lang/String;)V",
939 Dalvik_dalvik_system_VMDebug_dumpHprofData },
Andy McFadden6bf992c2010-01-28 17:01:39 -0800940 { "dumpHprofDataDdms", "()V",
941 Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms },
Andy McFadden9faa9e62009-04-08 00:35:55 -0700942 { "cacheRegisterMap", "(Ljava/lang/String;)Z",
943 Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
Andy McFadden92fa4762009-10-22 17:24:45 -0700944 { "dumpReferenceTables", "()V",
945 Dalvik_dalvik_system_VMDebug_dumpReferenceTables },
Andy McFaddene9efb8a2009-07-31 13:54:59 -0700946 { "crash", "()V",
947 Dalvik_dalvik_system_VMDebug_crash },
Ben Cheng7d656dd2010-03-12 16:11:49 -0800948 { "infopoint", "(I)V",
949 Dalvik_dalvik_system_VMDebug_infopoint },
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800950 { NULL, NULL, NULL },
951};