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