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