blob: 1d2f024f78b25b580cff0e3e2bde0e9d61b6229c [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 {
111 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#if PROFILE_EXTERNAL_ALLOCATIONS
117 KIND_EXT_ALLOCATED_OBJECTS = 1<<12,
118 KIND_EXT_ALLOCATED_BYTES = 1<<13,
119 KIND_EXT_FREED_OBJECTS = 1<<14,
120 KIND_EXT_FREED_BYTES = 1<<15,
121#endif // PROFILE_EXTERNAL_ALLOCATIONS
122
123 KIND_GLOBAL_ALLOCATED_OBJECTS = KIND_ALLOCATED_OBJECTS,
124 KIND_GLOBAL_ALLOCATED_BYTES = KIND_ALLOCATED_BYTES,
125 KIND_GLOBAL_FREED_OBJECTS = KIND_FREED_OBJECTS,
126 KIND_GLOBAL_FREED_BYTES = KIND_FREED_BYTES,
127 KIND_GLOBAL_GC_INVOCATIONS = KIND_GC_INVOCATIONS,
128#if PROFILE_EXTERNAL_ALLOCATIONS
129 KIND_GLOBAL_EXT_ALLOCATED_OBJECTS = KIND_EXT_ALLOCATED_OBJECTS,
130 KIND_GLOBAL_EXT_ALLOCATED_BYTES = KIND_EXT_ALLOCATED_BYTES,
131 KIND_GLOBAL_EXT_FREED_OBJECTS = KIND_EXT_FREED_OBJECTS,
132 KIND_GLOBAL_EXT_FREED_BYTES = KIND_EXT_FREED_BYTES,
133#endif // PROFILE_EXTERNAL_ALLOCATIONS
134
135 KIND_THREAD_ALLOCATED_OBJECTS = KIND_ALLOCATED_OBJECTS << 16,
136 KIND_THREAD_ALLOCATED_BYTES = KIND_ALLOCATED_BYTES << 16,
137 KIND_THREAD_FREED_OBJECTS = KIND_FREED_OBJECTS << 16,
138 KIND_THREAD_FREED_BYTES = KIND_FREED_BYTES << 16,
139#if PROFILE_EXTERNAL_ALLOCATIONS
140 KIND_THREAD_EXT_ALLOCATED_OBJECTS = KIND_EXT_ALLOCATED_OBJECTS << 16,
141 KIND_THREAD_EXT_ALLOCATED_BYTES = KIND_EXT_ALLOCATED_BYTES << 16,
142 KIND_THREAD_EXT_FREED_OBJECTS = KIND_EXT_FREED_OBJECTS << 16,
143 KIND_THREAD_EXT_FREED_BYTES = KIND_EXT_FREED_BYTES << 16,
144#endif // PROFILE_EXTERNAL_ALLOCATIONS
145 KIND_THREAD_GC_INVOCATIONS = KIND_GC_INVOCATIONS << 16,
146
147 // TODO: failedAllocCount, failedAllocSize
148};
149
150#define KIND_ALL_COUNTS 0xffffffff
151
152/*
153 * Zero out the specified fields.
154 */
155static void clearAllocProfStateFields(AllocProfState *allocProf,
156 unsigned int kinds)
157{
158 if (kinds & KIND_ALLOCATED_OBJECTS) {
159 allocProf->allocCount = 0;
160 }
161 if (kinds & KIND_ALLOCATED_BYTES) {
162 allocProf->allocSize = 0;
163 }
164 if (kinds & KIND_FREED_OBJECTS) {
165 allocProf->freeCount = 0;
166 }
167 if (kinds & KIND_FREED_BYTES) {
168 allocProf->freeSize = 0;
169 }
170 if (kinds & KIND_GC_INVOCATIONS) {
171 allocProf->gcCount = 0;
172 }
173#if PROFILE_EXTERNAL_ALLOCATIONS
174 if (kinds & KIND_EXT_ALLOCATED_OBJECTS) {
175 allocProf->externalAllocCount = 0;
176 }
177 if (kinds & KIND_EXT_ALLOCATED_BYTES) {
178 allocProf->externalAllocSize = 0;
179 }
180 if (kinds & KIND_EXT_FREED_OBJECTS) {
181 allocProf->externalFreeCount = 0;
182 }
183 if (kinds & KIND_EXT_FREED_BYTES) {
184 allocProf->externalFreeSize = 0;
185 }
186#endif // PROFILE_EXTERNAL_ALLOCATIONS
187}
188#endif
189
190/*
191 * static void startAllocCounting()
192 *
193 * Reset the counters and enable counting.
194 *
195 * TODO: this currently only resets the per-thread counters for the current
196 * thread. If we actually start using the per-thread counters we'll
197 * probably want to fix this.
198 */
199static void Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4* args,
200 JValue* pResult)
201{
202 UNUSED_PARAMETER(args);
203
204#ifdef WITH_PROFILER
205 clearAllocProfStateFields(&gDvm.allocProf, KIND_ALL_COUNTS);
206 clearAllocProfStateFields(&dvmThreadSelf()->allocProf, KIND_ALL_COUNTS);
207 dvmStartAllocCounting();
208#endif
209 RETURN_VOID();
210}
211
212/*
213 * public static void stopAllocCounting()
214 */
215static void Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4* args,
216 JValue* pResult)
217{
218 UNUSED_PARAMETER(args);
219
220#ifdef WITH_PROFILER
221 dvmStopAllocCounting();
222#endif
223 RETURN_VOID();
224}
225
226/*
227 * private static int getAllocCount(int kind)
228 */
229static void Dalvik_dalvik_system_VMDebug_getAllocCount(const u4* args,
230 JValue* pResult)
231{
232#ifdef WITH_PROFILER
233 AllocProfState *allocProf;
234 unsigned int kind = args[0];
235 if (kind < (1<<16)) {
236 allocProf = &gDvm.allocProf;
237 } else {
238 allocProf = &dvmThreadSelf()->allocProf;
239 kind >>= 16;
240 }
241 switch (kind) {
242 case KIND_ALLOCATED_OBJECTS:
243 pResult->i = allocProf->allocCount;
244 break;
245 case KIND_ALLOCATED_BYTES:
246 pResult->i = allocProf->allocSize;
247 break;
248 case KIND_FREED_OBJECTS:
249 pResult->i = allocProf->freeCount;
250 break;
251 case KIND_FREED_BYTES:
252 pResult->i = allocProf->freeSize;
253 break;
254 case KIND_GC_INVOCATIONS:
255 pResult->i = allocProf->gcCount;
256 break;
257#if PROFILE_EXTERNAL_ALLOCATIONS
258 case KIND_EXT_ALLOCATED_OBJECTS:
259 pResult->i = allocProf->externalAllocCount;
260 break;
261 case KIND_EXT_ALLOCATED_BYTES:
262 pResult->i = allocProf->externalAllocSize;
263 break;
264 case KIND_EXT_FREED_OBJECTS:
265 pResult->i = allocProf->externalFreeCount;
266 break;
267 case KIND_EXT_FREED_BYTES:
268 pResult->i = allocProf->externalFreeSize;
269 break;
270#endif // PROFILE_EXTERNAL_ALLOCATIONS
271 default:
272 assert(false);
273 pResult->i = -1;
274 }
275#else
276 RETURN_INT(-1);
277#endif
278}
279
280/*
281 * public static void resetAllocCount(int kinds)
282 */
283static void Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4* args,
284 JValue* pResult)
285{
286#ifdef WITH_PROFILER
287 unsigned int kinds = args[0];
288 clearAllocProfStateFields(&gDvm.allocProf, kinds & 0xffff);
289 clearAllocProfStateFields(&dvmThreadSelf()->allocProf, kinds >> 16);
290#endif
291 RETURN_VOID();
292}
293
294/*
Andy McFadden01718122010-01-22 16:36:30 -0800295 * static void startMethodTracingNative(String traceFileName,
296 * FileDescriptor fd, int bufferSize, int flags)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800297 *
298 * Start method trace profiling.
Andy McFadden01718122010-01-22 16:36:30 -0800299 *
300 * If both "traceFileName" and "fd" are null, the result will be sent
301 * directly to DDMS. (The non-DDMS versions of the calls are expected
302 * to enforce non-NULL filenames.)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800303 */
Andy McFadden01718122010-01-22 16:36:30 -0800304static void Dalvik_dalvik_system_VMDebug_startMethodTracingNative(const u4* args,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800305 JValue* pResult)
306{
307#ifdef WITH_PROFILER
308 StringObject* traceFileStr = (StringObject*) args[0];
Dianne Hackborn0f0ae022009-06-23 19:21:10 -0700309 DataObject* traceFd = (DataObject*) args[1];
310 int bufferSize = args[2];
311 int flags = args[3];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800312
313 if (bufferSize == 0) {
314 // Default to 8MB per the documentation.
315 bufferSize = 8 * 1024 * 1024;
316 }
317
Andy McFadden01718122010-01-22 16:36:30 -0800318 if (bufferSize < 1024) {
Dianne Hackborn0f0ae022009-06-23 19:21:10 -0700319 dvmThrowException("Ljava/lang/IllegalArgumentException;", NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800320 RETURN_VOID();
321 }
322
Andy McFadden01718122010-01-22 16:36:30 -0800323 char* traceFileName = NULL;
324 if (traceFileStr != NULL)
325 traceFileName = dvmCreateCstrFromString(traceFileStr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800326
Dianne Hackborn0f0ae022009-06-23 19:21:10 -0700327 int fd = -1;
328 if (traceFd != NULL) {
Andy McFadden01718122010-01-22 16:36:30 -0800329 InstField* field =
330 dvmFindInstanceField(traceFd->obj.clazz, "descriptor", "I");
Dianne Hackborn0f0ae022009-06-23 19:21:10 -0700331 if (field == NULL) {
332 dvmThrowException("Ljava/lang/NoSuchFieldException;",
333 "No FileDescriptor.descriptor field");
334 RETURN_VOID();
335 }
336 fd = dup(dvmGetFieldInt(&traceFd->obj, field->byteOffset));
Andy McFadden01718122010-01-22 16:36:30 -0800337 if (fd < 0) {
338 dvmThrowExceptionFmt("Ljava/lang/RuntimeException;",
339 "dup() failed: %s", strerror(errno));
340 RETURN_VOID();
341 }
Dianne Hackborn0f0ae022009-06-23 19:21:10 -0700342 }
343
Andy McFadden01718122010-01-22 16:36:30 -0800344 dvmMethodTraceStart(traceFileName != NULL ? traceFileName : "[DDMS]",
345 fd, bufferSize, flags, (traceFileName == NULL && fd == -1));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800346 free(traceFileName);
347#else
348 // throw exception?
349#endif
350 RETURN_VOID();
351}
352
353/*
The Android Open Source Project99409882009-03-18 22:20:24 -0700354 * static boolean isMethodTracingActive()
355 *
356 * Determine whether method tracing is currently active.
357 */
358static void Dalvik_dalvik_system_VMDebug_isMethodTracingActive(const u4* args,
359 JValue* pResult)
360{
361 UNUSED_PARAMETER(args);
362
363#ifdef WITH_PROFILER
364 RETURN_BOOLEAN(dvmIsMethodTraceActive());
365#else
366 RETURN_BOOLEAN(false);
367#endif
368}
369
370/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800371 * static void stopMethodTracing()
372 *
373 * Stop method tracing.
374 */
375static void Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4* args,
376 JValue* pResult)
377{
378 UNUSED_PARAMETER(args);
379
380#ifdef WITH_PROFILER
381 dvmMethodTraceStop();
382#else
383 // throw exception?
384#endif
385 RETURN_VOID();
386}
387
388/*
389 * static void startEmulatorTracing()
390 *
391 * Start sending method trace info to the emulator.
392 */
393static void Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4* args,
394 JValue* pResult)
395{
396 UNUSED_PARAMETER(args);
397
398#ifdef WITH_PROFILER
399 dvmEmulatorTraceStart();
400#else
401 // throw exception?
402#endif
403 RETURN_VOID();
404}
405
406/*
407 * static void stopEmulatorTracing()
408 *
409 * Start sending method trace info to the emulator.
410 */
411static void Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4* args,
412 JValue* pResult)
413{
414 UNUSED_PARAMETER(args);
415
416#ifdef WITH_PROFILER
417 dvmEmulatorTraceStop();
418#else
419 // throw exception?
420#endif
421 RETURN_VOID();
422}
423
424/*
425 * static int setAllocationLimit(int limit)
426 *
427 * Set the current allocation limit in this thread. Return the previous
428 * value.
429 */
430static void Dalvik_dalvik_system_VMDebug_setAllocationLimit(const u4* args,
431 JValue* pResult)
432{
433#if defined(WITH_ALLOC_LIMITS)
434 gDvm.checkAllocLimits = true;
435
436 Thread* self = dvmThreadSelf();
437 int newLimit = args[0];
438 int oldLimit = self->allocLimit;
439
440 if (newLimit < -1) {
441 LOGE("WARNING: bad limit request (%d)\n", newLimit);
442 newLimit = -1;
443 }
444 self->allocLimit = newLimit;
445 RETURN_INT(oldLimit);
446#else
447 UNUSED_PARAMETER(args);
448 RETURN_INT(-1);
449#endif
450}
451
452/*
453 * static int setGlobalAllocationLimit(int limit)
454 *
455 * Set the allocation limit for this process. Returns the previous value.
456 */
457static void Dalvik_dalvik_system_VMDebug_setGlobalAllocationLimit(const u4* args,
458 JValue* pResult)
459{
460#if defined(WITH_ALLOC_LIMITS)
461 gDvm.checkAllocLimits = true;
462
463 int newLimit = args[0];
464 int oldLimit = gDvm.allocationLimit;
465
466 if (newLimit < -1 || newLimit > 0) {
467 LOGE("WARNING: bad limit request (%d)\n", newLimit);
468 newLimit = -1;
469 }
470 // TODO: should use an atomic swap here
471 gDvm.allocationLimit = newLimit;
472 RETURN_INT(oldLimit);
473#else
474 UNUSED_PARAMETER(args);
475 RETURN_INT(-1);
476#endif
477}
478
479/*
480 * static boolean isDebuggerConnected()
481 *
482 * Returns "true" if a debugger is attached.
483 */
484static void Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4* args,
485 JValue* pResult)
486{
487 UNUSED_PARAMETER(args);
488
489 RETURN_BOOLEAN(dvmDbgIsDebuggerConnected());
490}
491
492/*
493 * static boolean isDebuggingEnabled()
494 *
495 * Returns "true" if debugging is enabled.
496 */
497static void Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4* args,
498 JValue* pResult)
499{
500 UNUSED_PARAMETER(args);
501
502 RETURN_BOOLEAN(gDvm.jdwpConfigured);
503}
504
505/*
506 * static long lastDebuggerActivity()
507 *
508 * Returns the time, in msec, since we last had an interaction with the
509 * debugger (send or receive).
510 */
511static void Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4* args,
512 JValue* pResult)
513{
514 UNUSED_PARAMETER(args);
515
516 RETURN_LONG(dvmDbgLastDebuggerActivity());
517}
518
519/*
520 * static void startInstructionCounting()
521 */
522static void Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4* args,
523 JValue* pResult)
524{
525#if defined(WITH_PROFILER)
526 dvmStartInstructionCounting();
527#else
528 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
529#endif
530 RETURN_VOID();
531}
532
533/*
534 * static void stopInstructionCounting()
535 */
536static void Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4* args,
537 JValue* pResult)
538{
539#if defined(WITH_PROFILER)
540 dvmStopInstructionCounting();
541#else
542 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
543#endif
544 RETURN_VOID();
545}
546
547/*
548 * static boolean getInstructionCount(int[] counts)
549 *
550 * Grab a copy of the global instruction count array.
551 *
552 * Since the instruction counts aren't synchronized, we use sched_yield
553 * to improve our chances of finishing without contention. (Only makes
554 * sense on a uniprocessor.)
555 */
556static void Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4* args,
557 JValue* pResult)
558{
559#if defined(WITH_PROFILER)
560 ArrayObject* countArray = (ArrayObject*) args[0];
561 int* storage;
562
563 storage = (int*) countArray->contents;
564 sched_yield();
565 memcpy(storage, gDvm.executedInstrCounts,
566 kNumDalvikInstructions * sizeof(int));
567#else
568 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
569#endif
570 RETURN_VOID();
571}
572
573/*
574 * static boolean resetInstructionCount()
575 *
576 * Reset the instruction count array.
577 */
578static void Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4* args,
579 JValue* pResult)
580{
581#if defined(WITH_PROFILER)
582 sched_yield();
583 memset(gDvm.executedInstrCounts, 0, kNumDalvikInstructions * sizeof(int));
584#else
585 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
586#endif
587 RETURN_VOID();
588}
589
590/*
591 * static void printLoadedClasses(int flags)
592 *
593 * Dump the list of loaded classes.
594 */
595static void Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4* args,
596 JValue* pResult)
597{
598 int flags = args[0];
599
600 dvmDumpAllClasses(flags);
601
602 RETURN_VOID();
603}
604
605/*
606 * static int getLoadedClassCount()
607 *
608 * Return the number of loaded classes
609 */
610static void Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4* args,
611 JValue* pResult)
612{
613 int count;
614
615 UNUSED_PARAMETER(args);
616
617 count = dvmGetNumLoadedClasses();
618
619 RETURN_INT(count);
620}
621
622/*
623 * Returns the thread-specific CPU-time clock value for the current thread,
624 * or -1 if the feature isn't supported.
625 */
626static void Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4* args,
627 JValue* pResult)
628{
629 jlong result;
630
631#ifdef HAVE_POSIX_CLOCKS
632 struct timespec now;
633 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
634 result = (jlong) (now.tv_sec*1000000000LL + now.tv_nsec);
635#else
636 result = (jlong) -1;
637#endif
638
639 RETURN_LONG(result);
640}
641
642/*
643 * static void dumpHprofData(String fileName)
644 *
645 * Cause "hprof" data to be dumped. We can throw an IOException if an
646 * error occurs during file handling.
647 */
648static void Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4* args,
649 JValue* pResult)
650{
651#ifdef WITH_HPROF
652 StringObject* fileNameStr = (StringObject*) args[0];
653 char* fileName;
The Android Open Source Project99409882009-03-18 22:20:24 -0700654 int result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800655
656 if (fileNameStr == NULL) {
657 dvmThrowException("Ljava/lang/NullPointerException;", NULL);
658 RETURN_VOID();
659 }
660
661 fileName = dvmCreateCstrFromString(fileNameStr);
662 if (fileName == NULL) {
663 /* unexpected -- malloc failure? */
664 dvmThrowException("Ljava/lang/RuntimeException;", "malloc failure?");
665 RETURN_VOID();
666 }
667
Andy McFadden6bf992c2010-01-28 17:01:39 -0800668 result = hprofDumpHeap(fileName, false);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800669 free(fileName);
The Android Open Source Project99409882009-03-18 22:20:24 -0700670
671 if (result != 0) {
672 /* ideally we'd throw something more specific based on actual failure */
673 dvmThrowException("Ljava/lang/RuntimeException;",
674 "Failure during heap dump -- check log output for details");
675 RETURN_VOID();
676 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800677#else
678 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
679#endif
680
681 RETURN_VOID();
682}
683
Andy McFadden9faa9e62009-04-08 00:35:55 -0700684/*
Andy McFadden6bf992c2010-01-28 17:01:39 -0800685 * static void dumpHprofDataDdms()
686 *
687 * Cause "hprof" data to be computed and sent directly to DDMS.
688 */
689static void Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4* args,
690 JValue* pResult)
691{
692#ifdef WITH_HPROF
693 int result;
694
695 result = hprofDumpHeap("[DDMS]", true);
696
697 if (result != 0) {
698 /* ideally we'd throw something more specific based on actual failure */
699 dvmThrowException("Ljava/lang/RuntimeException;",
700 "Failure during heap dump -- check log output for details");
701 RETURN_VOID();
702 }
703#else
704 dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
705#endif
706
707 RETURN_VOID();
708}
709
710/*
Andy McFadden9faa9e62009-04-08 00:35:55 -0700711 * static boolean cacheRegisterMap(String classAndMethodDescr)
712 *
713 * If the specified class is loaded, and the named method exists, ensure
714 * that the method's register map is ready for use. If the class/method
715 * cannot be found, nothing happens.
716 *
717 * This can improve the zygote's sharing of compressed register maps. Do
718 * this after class preloading.
719 *
720 * Returns true if the register map is cached and ready, either as a result
721 * of this call or earlier activity. Returns false if the class isn't loaded,
722 * if the method couldn't be found, or if the method has no register map.
723 *
724 * (Uncomment logs in dvmGetExpandedRegisterMap0() to gather stats.)
725 */
726static void Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4* args,
727 JValue* pResult)
728{
729 StringObject* classAndMethodDescStr = (StringObject*) args[0];
730 ClassObject* clazz;
731 bool result = false;
732
733 if (classAndMethodDescStr == NULL) {
734 dvmThrowException("Ljava/lang/NullPointerException;", NULL);
735 RETURN_VOID();
736 }
737
738 char* classAndMethodDesc = NULL;
739
740 /*
741 * Pick the string apart. We have a local copy, so just modify it
742 * in place.
743 */
744 classAndMethodDesc = dvmCreateCstrFromString(classAndMethodDescStr);
745
746 char* methodName = strchr(classAndMethodDesc, '.');
747 if (methodName == NULL) {
748 dvmThrowException("Ljava/lang/RuntimeException;",
749 "method name not found in string");
750 RETURN_VOID();
751 }
752 *methodName++ = '\0';
753
754 char* methodDescr = strchr(methodName, ':');
755 if (methodDescr == NULL) {
756 dvmThrowException("Ljava/lang/RuntimeException;",
757 "method descriptor not found in string");
758 RETURN_VOID();
759 }
760 *methodDescr++ = '\0';
761
762 //LOGD("GOT: %s %s %s\n", classAndMethodDesc, methodName, methodDescr);
763
764 /*
765 * Find the class, but only if it's already loaded.
766 */
767 clazz = dvmLookupClass(classAndMethodDesc, NULL, false);
768 if (clazz == NULL) {
769 LOGD("Class %s not found in bootstrap loader\n", classAndMethodDesc);
770 goto bail;
771 }
772
773 Method* method;
774
775 /*
776 * Find the method, which could be virtual or direct, defined directly
777 * or inherited.
778 */
779 if (methodName[0] == '<') {
780 /*
781 * Constructor or class initializer. Only need to examine the
782 * "direct" list, and don't need to search up the class hierarchy.
783 */
784 method = dvmFindDirectMethodByDescriptor(clazz, methodName,
785 methodDescr);
786 } else {
787 /*
788 * Try both lists, and scan up the tree.
789 */
790 method = dvmFindVirtualMethodHierByDescriptor(clazz, methodName,
791 methodDescr);
792 if (method == NULL) {
793 method = dvmFindDirectMethodHierByDescriptor(clazz, methodName,
794 methodDescr);
795 }
796 }
797
798 if (method != NULL) {
799 /*
800 * Got it. See if there's a register map here.
801 */
802 const RegisterMap* pMap;
803 pMap = dvmGetExpandedRegisterMap(method);
804 if (pMap == NULL) {
805 LOGV("No map for %s.%s %s\n",
806 classAndMethodDesc, methodName, methodDescr);
807 } else {
808 LOGV("Found map %s.%s %s\n",
809 classAndMethodDesc, methodName, methodDescr);
810 result = true;
811 }
812 } else {
813 LOGV("Unable to find %s.%s %s\n",
814 classAndMethodDesc, methodName, methodDescr);
815 }
816
817bail:
818 free(classAndMethodDesc);
819 RETURN_BOOLEAN(result);
820}
821
Andy McFaddene9efb8a2009-07-31 13:54:59 -0700822/*
Andy McFadden92fa4762009-10-22 17:24:45 -0700823 * static void dumpReferenceTables()
824 */
825static void Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4* args,
826 JValue* pResult)
827{
828 UNUSED_PARAMETER(args);
829 UNUSED_PARAMETER(pResult);
830
831 LOGI("--- reference table dump ---\n");
832 dvmDumpJniReferenceTables();
833 // could dump thread's internalLocalRefTable, probably not useful
834 // ditto for thread's jniMonitorRefTable
835 LOGI("---\n");
836 RETURN_VOID();
837}
838
839/*
Andy McFaddene9efb8a2009-07-31 13:54:59 -0700840 * static void crash()
841 *
842 * Dump the current thread's interpreted stack and abort the VM. Useful
843 * for seeing both interpreted and native stack traces.
844 *
845 * (Might want to restrict this to debuggable processes as a security
846 * measure, or check SecurityManager.checkExit().)
847 */
848static void Dalvik_dalvik_system_VMDebug_crash(const u4* args,
849 JValue* pResult)
850{
851 UNUSED_PARAMETER(args);
852 UNUSED_PARAMETER(pResult);
853
854 LOGW("Crashing VM on request\n");
855 dvmDumpThread(dvmThreadSelf(), false);
856 dvmAbort();
857}
858
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800859const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = {
Andy McFaddenfd52c652010-01-22 07:23:40 -0800860 { "getVmFeatureList", "()[Ljava/lang/String;",
861 Dalvik_dalvik_system_VMDebug_getVmFeatureList },
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800862 { "getAllocCount", "(I)I",
863 Dalvik_dalvik_system_VMDebug_getAllocCount },
864 { "resetAllocCount", "(I)V",
865 Dalvik_dalvik_system_VMDebug_resetAllocCount },
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800866 { "startAllocCounting", "()V",
867 Dalvik_dalvik_system_VMDebug_startAllocCounting },
868 { "stopAllocCounting", "()V",
869 Dalvik_dalvik_system_VMDebug_stopAllocCounting },
Andy McFadden01718122010-01-22 16:36:30 -0800870 { "startMethodTracingNative", "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V",
871 Dalvik_dalvik_system_VMDebug_startMethodTracingNative },
The Android Open Source Project99409882009-03-18 22:20:24 -0700872 { "isMethodTracingActive", "()Z",
873 Dalvik_dalvik_system_VMDebug_isMethodTracingActive },
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800874 { "stopMethodTracing", "()V",
875 Dalvik_dalvik_system_VMDebug_stopMethodTracing },
876 { "startEmulatorTracing", "()V",
877 Dalvik_dalvik_system_VMDebug_startEmulatorTracing },
878 { "stopEmulatorTracing", "()V",
879 Dalvik_dalvik_system_VMDebug_stopEmulatorTracing },
880 { "setAllocationLimit", "(I)I",
881 Dalvik_dalvik_system_VMDebug_setAllocationLimit },
882 { "setGlobalAllocationLimit", "(I)I",
883 Dalvik_dalvik_system_VMDebug_setGlobalAllocationLimit },
884 { "startInstructionCounting", "()V",
885 Dalvik_dalvik_system_VMDebug_startInstructionCounting },
886 { "stopInstructionCounting", "()V",
887 Dalvik_dalvik_system_VMDebug_stopInstructionCounting },
888 { "resetInstructionCount", "()V",
889 Dalvik_dalvik_system_VMDebug_resetInstructionCount },
890 { "getInstructionCount", "([I)V",
891 Dalvik_dalvik_system_VMDebug_getInstructionCount },
892 { "isDebuggerConnected", "()Z",
893 Dalvik_dalvik_system_VMDebug_isDebuggerConnected },
894 { "isDebuggingEnabled", "()Z",
895 Dalvik_dalvik_system_VMDebug_isDebuggingEnabled },
896 { "lastDebuggerActivity", "()J",
897 Dalvik_dalvik_system_VMDebug_lastDebuggerActivity },
898 { "printLoadedClasses", "(I)V",
899 Dalvik_dalvik_system_VMDebug_printLoadedClasses },
900 { "getLoadedClassCount", "()I",
901 Dalvik_dalvik_system_VMDebug_getLoadedClassCount },
902 { "threadCpuTimeNanos", "()J",
903 Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
904 { "dumpHprofData", "(Ljava/lang/String;)V",
905 Dalvik_dalvik_system_VMDebug_dumpHprofData },
Andy McFadden6bf992c2010-01-28 17:01:39 -0800906 { "dumpHprofDataDdms", "()V",
907 Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms },
Andy McFadden9faa9e62009-04-08 00:35:55 -0700908 { "cacheRegisterMap", "(Ljava/lang/String;)Z",
909 Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
Andy McFadden92fa4762009-10-22 17:24:45 -0700910 { "dumpReferenceTables", "()V",
911 Dalvik_dalvik_system_VMDebug_dumpReferenceTables },
Andy McFaddene9efb8a2009-07-31 13:54:59 -0700912 { "crash", "()V",
913 Dalvik_dalvik_system_VMDebug_crash },
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800914 { NULL, NULL, NULL },
915};
916