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