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