1/*
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 "alloc/HeapSource.h"
22#include "native/InternalNativePriv.h"
23#include "hprof/Hprof.h"
24
25#include <string.h>
26#include <unistd.h>
27
28
29/*
30 * Extracts the fd from a FileDescriptor object.
31 *
32 * If an error is encountered, or the extracted descriptor is numerically
33 * invalid, this returns -1 with an exception raised.
34 */
35static int getFileDescriptor(Object* obj)
36{
37    assert(obj != NULL);
38    assert(strcmp(obj->clazz->descriptor, "Ljava/io/FileDescriptor;") == 0);
39
40    int fd = dvmGetFieldInt(obj, gDvm.offJavaIoFileDescriptor_descriptor);
41    if (fd < 0) {
42        dvmThrowRuntimeException("Invalid file descriptor");
43        return -1;
44    }
45
46    return fd;
47}
48
49/*
50 * static String[] getVmFeatureList()
51 *
52 * Return a set of strings describing available VM features (this is chiefly
53 * of interest to DDMS).
54 */
55static void Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4* args, JValue* pResult) {
56    std::vector<std::string> features;
57    features.push_back("method-trace-profiling");
58    features.push_back("method-trace-profiling-streaming");
59    features.push_back("method-sample-profiling");
60    features.push_back("hprof-heap-dump");
61    features.push_back("hprof-heap-dump-streaming");
62
63    ArrayObject* result = dvmCreateStringArray(features);
64    dvmReleaseTrackedAlloc((Object*) result, dvmThreadSelf());
65    RETURN_PTR(result);
66}
67
68/* These must match the values in dalvik.system.VMDebug.
69 */
70enum {
71    KIND_ALLOCATED_OBJECTS      = 1<<0,
72    KIND_ALLOCATED_BYTES        = 1<<1,
73    KIND_FREED_OBJECTS          = 1<<2,
74    KIND_FREED_BYTES            = 1<<3,
75    KIND_GC_INVOCATIONS         = 1<<4,
76    KIND_CLASS_INIT_COUNT       = 1<<5,
77    KIND_CLASS_INIT_TIME        = 1<<6,
78
79    /* These values exist for backward compatibility. */
80    KIND_EXT_ALLOCATED_OBJECTS = 1<<12,
81    KIND_EXT_ALLOCATED_BYTES   = 1<<13,
82    KIND_EXT_FREED_OBJECTS     = 1<<14,
83    KIND_EXT_FREED_BYTES       = 1<<15,
84
85    KIND_GLOBAL_ALLOCATED_OBJECTS   = KIND_ALLOCATED_OBJECTS,
86    KIND_GLOBAL_ALLOCATED_BYTES     = KIND_ALLOCATED_BYTES,
87    KIND_GLOBAL_FREED_OBJECTS       = KIND_FREED_OBJECTS,
88    KIND_GLOBAL_FREED_BYTES         = KIND_FREED_BYTES,
89    KIND_GLOBAL_GC_INVOCATIONS      = KIND_GC_INVOCATIONS,
90    KIND_GLOBAL_CLASS_INIT_COUNT    = KIND_CLASS_INIT_COUNT,
91    KIND_GLOBAL_CLASS_INIT_TIME     = KIND_CLASS_INIT_TIME,
92
93    KIND_THREAD_ALLOCATED_OBJECTS   = KIND_ALLOCATED_OBJECTS << 16,
94    KIND_THREAD_ALLOCATED_BYTES     = KIND_ALLOCATED_BYTES << 16,
95    KIND_THREAD_FREED_OBJECTS       = KIND_FREED_OBJECTS << 16,
96    KIND_THREAD_FREED_BYTES         = KIND_FREED_BYTES << 16,
97
98    KIND_THREAD_GC_INVOCATIONS      = KIND_GC_INVOCATIONS << 16,
99
100    // TODO: failedAllocCount, failedAllocSize
101};
102
103#define KIND_ALL_COUNTS 0xffffffff
104
105/*
106 * Zero out the specified fields.
107 */
108static void clearAllocProfStateFields(AllocProfState *allocProf,
109    unsigned int kinds)
110{
111    if (kinds & KIND_ALLOCATED_OBJECTS) {
112        allocProf->allocCount = 0;
113    }
114    if (kinds & KIND_ALLOCATED_BYTES) {
115        allocProf->allocSize = 0;
116    }
117    if (kinds & KIND_FREED_OBJECTS) {
118        allocProf->freeCount = 0;
119    }
120    if (kinds & KIND_FREED_BYTES) {
121        allocProf->freeSize = 0;
122    }
123    if (kinds & KIND_GC_INVOCATIONS) {
124        allocProf->gcCount = 0;
125    }
126    if (kinds & KIND_CLASS_INIT_COUNT) {
127        allocProf->classInitCount = 0;
128    }
129    if (kinds & KIND_CLASS_INIT_TIME) {
130        allocProf->classInitTime = 0;
131    }
132}
133
134/*
135 * static void startAllocCounting()
136 *
137 * Reset the counters and enable counting.
138 *
139 * TODO: this currently only resets the per-thread counters for the current
140 * thread.  If we actually start using the per-thread counters we'll
141 * probably want to fix this.
142 */
143static void Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4* args,
144    JValue* pResult)
145{
146    UNUSED_PARAMETER(args);
147
148    clearAllocProfStateFields(&gDvm.allocProf, KIND_ALL_COUNTS);
149    clearAllocProfStateFields(&dvmThreadSelf()->allocProf, KIND_ALL_COUNTS);
150    dvmStartAllocCounting();
151    RETURN_VOID();
152}
153
154/*
155 * public static void stopAllocCounting()
156 */
157static void Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4* args,
158    JValue* pResult)
159{
160    UNUSED_PARAMETER(args);
161
162    dvmStopAllocCounting();
163    RETURN_VOID();
164}
165
166/*
167 * private static int getAllocCount(int kind)
168 */
169static void Dalvik_dalvik_system_VMDebug_getAllocCount(const u4* args,
170    JValue* pResult)
171{
172    AllocProfState *allocProf;
173    unsigned int kind = args[0];
174    if (kind < (1<<16)) {
175        allocProf = &gDvm.allocProf;
176    } else {
177        allocProf = &dvmThreadSelf()->allocProf;
178        kind >>= 16;
179    }
180    switch (kind) {
181    case KIND_ALLOCATED_OBJECTS:
182        pResult->i = allocProf->allocCount;
183        break;
184    case KIND_ALLOCATED_BYTES:
185        pResult->i = allocProf->allocSize;
186        break;
187    case KIND_FREED_OBJECTS:
188        pResult->i = allocProf->freeCount;
189        break;
190    case KIND_FREED_BYTES:
191        pResult->i = allocProf->freeSize;
192        break;
193    case KIND_GC_INVOCATIONS:
194        pResult->i = allocProf->gcCount;
195        break;
196    case KIND_CLASS_INIT_COUNT:
197        pResult->i = allocProf->classInitCount;
198        break;
199    case KIND_CLASS_INIT_TIME:
200        /* convert nsec to usec, reduce to 32 bits */
201        pResult->i = (int) (allocProf->classInitTime / 1000);
202        break;
203    case KIND_EXT_ALLOCATED_OBJECTS:
204    case KIND_EXT_ALLOCATED_BYTES:
205    case KIND_EXT_FREED_OBJECTS:
206    case KIND_EXT_FREED_BYTES:
207        pResult->i = 0;  /* backward compatibility */
208        break;
209    default:
210        assert(false);
211        pResult->i = -1;
212    }
213}
214
215/*
216 * public static void resetAllocCount(int kinds)
217 */
218static void Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4* args,
219    JValue* pResult)
220{
221    unsigned int kinds = args[0];
222    clearAllocProfStateFields(&gDvm.allocProf, kinds & 0xffff);
223    clearAllocProfStateFields(&dvmThreadSelf()->allocProf, kinds >> 16);
224    RETURN_VOID();
225}
226
227/*
228 * static void startMethodTracingDdmsImpl(int bufferSize, int flags,
229 *     boolean samplingEnabled, int intervalUs)
230 *
231 * Start method trace profiling, sending results directly to DDMS.
232 */
233static void Dalvik_dalvik_system_VMDebug_startMethodTracingDdmsImpl(const u4* args,
234    JValue* pResult)
235{
236    int bufferSize = args[0];
237    int flags = args[1];
238    bool samplingEnabled = args[2];
239    int intervalUs = args[3];
240    dvmMethodTraceStart("[DDMS]", -1, bufferSize, flags, true, samplingEnabled,
241        intervalUs);
242    RETURN_VOID();
243}
244
245/*
246 * static void startMethodTracingFd(String traceFileName, FileDescriptor fd,
247 *     int bufferSize, int flags)
248 *
249 * Start method trace profiling, sending results to a file descriptor.
250 */
251static void Dalvik_dalvik_system_VMDebug_startMethodTracingFd(const u4* args,
252    JValue* pResult)
253{
254    StringObject* traceFileStr = (StringObject*) args[0];
255    Object* traceFd = (Object*) args[1];
256    int bufferSize = args[2];
257    int flags = args[3];
258
259    int origFd = getFileDescriptor(traceFd);
260    if (origFd < 0)
261        RETURN_VOID();
262
263    int fd = dup(origFd);
264    if (fd < 0) {
265        dvmThrowExceptionFmt(gDvm.exRuntimeException,
266            "dup(%d) failed: %s", origFd, strerror(errno));
267        RETURN_VOID();
268    }
269
270    char* traceFileName = dvmCreateCstrFromString(traceFileStr);
271    if (traceFileName == NULL) {
272        RETURN_VOID();
273    }
274
275    dvmMethodTraceStart(traceFileName, fd, bufferSize, flags, false, false, 0);
276    free(traceFileName);
277    RETURN_VOID();
278}
279
280/*
281 * static void startMethodTracingFilename(String traceFileName, int bufferSize,
282 *     int flags)
283 *
284 * Start method trace profiling, sending results to a file.
285 */
286static void Dalvik_dalvik_system_VMDebug_startMethodTracingFilename(const u4* args,
287    JValue* pResult)
288{
289    StringObject* traceFileStr = (StringObject*) args[0];
290    int bufferSize = args[1];
291    int flags = args[2];
292
293    char* traceFileName = dvmCreateCstrFromString(traceFileStr);
294    if (traceFileName == NULL) {
295        RETURN_VOID();
296    }
297
298    dvmMethodTraceStart(traceFileName, -1, bufferSize, flags, false, false, 0);
299    free(traceFileName);
300    RETURN_VOID();
301}
302
303/*
304 * static int getMethodTracingMode()
305 *
306 * Determine whether method tracing is currently active and what type is active.
307 */
308static void Dalvik_dalvik_system_VMDebug_getMethodTracingMode(const u4* args,
309    JValue* pResult)
310{
311    UNUSED_PARAMETER(args);
312
313    RETURN_INT(dvmGetMethodTracingMode());
314}
315
316/*
317 * static void stopMethodTracing()
318 *
319 * Stop method tracing.
320 */
321static void Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4* args,
322    JValue* pResult)
323{
324    UNUSED_PARAMETER(args);
325
326    dvmMethodTraceStop();
327    RETURN_VOID();
328}
329
330/*
331 * static void startEmulatorTracing()
332 *
333 * Start sending method trace info to the emulator.
334 */
335static void Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4* args,
336    JValue* pResult)
337{
338    UNUSED_PARAMETER(args);
339
340    dvmEmulatorTraceStart();
341    RETURN_VOID();
342}
343
344/*
345 * static void stopEmulatorTracing()
346 *
347 * Start sending method trace info to the emulator.
348 */
349static void Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4* args,
350    JValue* pResult)
351{
352    UNUSED_PARAMETER(args);
353
354    dvmEmulatorTraceStop();
355    RETURN_VOID();
356}
357
358/*
359 * static boolean isDebuggerConnected()
360 *
361 * Returns "true" if a debugger is attached.
362 */
363static void Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4* args,
364    JValue* pResult)
365{
366    UNUSED_PARAMETER(args);
367
368    RETURN_BOOLEAN(dvmDbgIsDebuggerConnected());
369}
370
371/*
372 * static boolean isDebuggingEnabled()
373 *
374 * Returns "true" if debugging is enabled.
375 */
376static void Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4* args,
377    JValue* pResult)
378{
379    UNUSED_PARAMETER(args);
380
381    RETURN_BOOLEAN(gDvm.jdwpConfigured);
382}
383
384/*
385 * static long lastDebuggerActivity()
386 *
387 * Returns the time, in msec, since we last had an interaction with the
388 * debugger (send or receive).
389 */
390static void Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4* args,
391    JValue* pResult)
392{
393    UNUSED_PARAMETER(args);
394
395    RETURN_LONG(dvmDbgLastDebuggerActivity());
396}
397
398/*
399 * static void startInstructionCounting()
400 */
401static void Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4* args,
402    JValue* pResult)
403{
404    dvmStartInstructionCounting();
405    RETURN_VOID();
406}
407
408/*
409 * static void stopInstructionCounting()
410 */
411static void Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4* args,
412    JValue* pResult)
413{
414    dvmStopInstructionCounting();
415    RETURN_VOID();
416}
417
418/*
419 * static boolean getInstructionCount(int[] counts)
420 *
421 * Grab a copy of the global instruction count array.
422 *
423 * Since the instruction counts aren't synchronized, we use sched_yield
424 * to improve our chances of finishing without contention.  (Only makes
425 * sense on a uniprocessor.)
426 */
427static void Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4* args,
428    JValue* pResult)
429{
430    ArrayObject* countArray = (ArrayObject*) args[0];
431
432    if (countArray != NULL) {
433        int* storage = (int*)(void*)countArray->contents;
434        u4 length = countArray->length;
435
436        /*
437         * Ensure that we copy at most kNumPackedOpcodes
438         * elements, but no more than the length of the given array.
439         */
440        if (length > kNumPackedOpcodes) {
441            length = kNumPackedOpcodes;
442        }
443
444        sched_yield();
445        memcpy(storage, gDvm.executedInstrCounts, length * sizeof(int));
446    }
447
448    RETURN_VOID();
449}
450
451/*
452 * static boolean resetInstructionCount()
453 *
454 * Reset the instruction count array.
455 */
456static void Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4* args,
457    JValue* pResult)
458{
459    sched_yield();
460    memset(gDvm.executedInstrCounts, 0, kNumPackedOpcodes * sizeof(int));
461    RETURN_VOID();
462}
463
464/*
465 * static void printLoadedClasses(int flags)
466 *
467 * Dump the list of loaded classes.
468 */
469static void Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4* args,
470    JValue* pResult)
471{
472    int flags = args[0];
473
474    dvmDumpAllClasses(flags);
475
476    RETURN_VOID();
477}
478
479/*
480 * static int getLoadedClassCount()
481 *
482 * Return the number of loaded classes
483 */
484static void Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4* args,
485    JValue* pResult)
486{
487    int count;
488
489    UNUSED_PARAMETER(args);
490
491    count = dvmGetNumLoadedClasses();
492
493    RETURN_INT(count);
494}
495
496/*
497 * Returns the thread-specific CPU-time clock value for the current thread,
498 * or -1 if the feature isn't supported.
499 */
500static void Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4* args,
501    JValue* pResult)
502{
503    jlong result;
504
505#ifdef HAVE_POSIX_CLOCKS
506    struct timespec now;
507    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
508    result = (jlong) (now.tv_sec*1000000000LL + now.tv_nsec);
509#else
510    result = (jlong) -1;
511#endif
512
513    RETURN_LONG(result);
514}
515
516/*
517 * static void dumpHprofData(String fileName, FileDescriptor fd)
518 *
519 * Cause "hprof" data to be dumped.  We can throw an IOException if an
520 * error occurs during file handling.
521 */
522static void Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4* args,
523    JValue* pResult)
524{
525    StringObject* fileNameStr = (StringObject*) args[0];
526    Object* fileDescriptor = (Object*) args[1];
527    char* fileName;
528    int result;
529
530    /*
531     * Only one of these may be NULL.
532     */
533    if (fileNameStr == NULL && fileDescriptor == NULL) {
534        dvmThrowNullPointerException("fileName == null && fd == null");
535        RETURN_VOID();
536    }
537
538    if (fileNameStr != NULL) {
539        fileName = dvmCreateCstrFromString(fileNameStr);
540        if (fileName == NULL) {
541            /* unexpected -- malloc failure? */
542            dvmThrowRuntimeException("malloc failure?");
543            RETURN_VOID();
544        }
545    } else {
546        fileName = strdup("[fd]");
547    }
548
549    int fd = -1;
550    if (fileDescriptor != NULL) {
551        fd = getFileDescriptor(fileDescriptor);
552        if (fd < 0) {
553            free(fileName);
554            RETURN_VOID();
555        }
556    }
557
558    result = hprofDumpHeap(fileName, fd, false);
559    free(fileName);
560
561    if (result != 0) {
562        /* ideally we'd throw something more specific based on actual failure */
563        dvmThrowRuntimeException(
564            "Failure during heap dump; check log output for details");
565        RETURN_VOID();
566    }
567
568    RETURN_VOID();
569}
570
571/*
572 * static void dumpHprofDataDdms()
573 *
574 * Cause "hprof" data to be computed and sent directly to DDMS.
575 */
576static void Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4* args,
577    JValue* pResult)
578{
579    int result;
580
581    result = hprofDumpHeap("[DDMS]", -1, true);
582
583    if (result != 0) {
584        /* ideally we'd throw something more specific based on actual failure */
585        dvmThrowRuntimeException(
586            "Failure during heap dump; check log output for details");
587        RETURN_VOID();
588    }
589
590    RETURN_VOID();
591}
592
593/*
594 * static boolean cacheRegisterMap(String classAndMethodDescr)
595 *
596 * If the specified class is loaded, and the named method exists, ensure
597 * that the method's register map is ready for use.  If the class/method
598 * cannot be found, nothing happens.
599 *
600 * This can improve the zygote's sharing of compressed register maps.  Do
601 * this after class preloading.
602 *
603 * Returns true if the register map is cached and ready, either as a result
604 * of this call or earlier activity.  Returns false if the class isn't loaded,
605 * if the method couldn't be found, or if the method has no register map.
606 *
607 * (Uncomment logs in dvmGetExpandedRegisterMap0() to gather stats.)
608 */
609static void Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4* args,
610    JValue* pResult)
611{
612    StringObject* classAndMethodDescStr = (StringObject*) args[0];
613    ClassObject* clazz;
614    bool result = false;
615
616    if (classAndMethodDescStr == NULL) {
617        dvmThrowNullPointerException("classAndMethodDesc == null");
618        RETURN_VOID();
619    }
620
621    char* classAndMethodDesc = NULL;
622
623    /*
624     * Pick the string apart.  We have a local copy, so just modify it
625     * in place.
626     */
627    classAndMethodDesc = dvmCreateCstrFromString(classAndMethodDescStr);
628
629    char* methodName = strchr(classAndMethodDesc, '.');
630    if (methodName == NULL) {
631        dvmThrowRuntimeException("method name not found in string");
632        RETURN_VOID();
633    }
634    *methodName++ = '\0';
635
636    char* methodDescr = strchr(methodName, ':');
637    if (methodDescr == NULL) {
638        dvmThrowRuntimeException("method descriptor not found in string");
639        RETURN_VOID();
640    }
641    *methodDescr++ = '\0';
642
643    //ALOGD("GOT: %s %s %s", classAndMethodDesc, methodName, methodDescr);
644
645    /*
646     * Find the class, but only if it's already loaded.
647     */
648    clazz = dvmLookupClass(classAndMethodDesc, NULL, false);
649    if (clazz == NULL) {
650        ALOGD("Class %s not found in bootstrap loader", classAndMethodDesc);
651        goto bail;
652    }
653
654    Method* method;
655
656    /*
657     * Find the method, which could be virtual or direct, defined directly
658     * or inherited.
659     */
660    if (methodName[0] == '<') {
661        /*
662         * Constructor or class initializer.  Only need to examine the
663         * "direct" list, and don't need to search up the class hierarchy.
664         */
665        method = dvmFindDirectMethodByDescriptor(clazz, methodName,
666                    methodDescr);
667    } else {
668        /*
669         * Try both lists, and scan up the tree.
670         */
671        method = dvmFindVirtualMethodHierByDescriptor(clazz, methodName,
672                    methodDescr);
673        if (method == NULL) {
674            method = dvmFindDirectMethodHierByDescriptor(clazz, methodName,
675                        methodDescr);
676        }
677    }
678
679    if (method != NULL) {
680        /*
681         * Got it.  See if there's a register map here.
682         */
683        const RegisterMap* pMap;
684        pMap = dvmGetExpandedRegisterMap(method);
685        if (pMap == NULL) {
686            ALOGV("No map for %s.%s %s",
687                classAndMethodDesc, methodName, methodDescr);
688        } else {
689            ALOGV("Found map %s.%s %s",
690                classAndMethodDesc, methodName, methodDescr);
691            result = true;
692        }
693    } else {
694        ALOGV("Unable to find %s.%s %s",
695            classAndMethodDesc, methodName, methodDescr);
696    }
697
698bail:
699    free(classAndMethodDesc);
700    RETURN_BOOLEAN(result);
701}
702
703/*
704 * static void dumpReferenceTables()
705 */
706static void Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4* args,
707    JValue* pResult)
708{
709    UNUSED_PARAMETER(args);
710    UNUSED_PARAMETER(pResult);
711
712    ALOGI("--- reference table dump ---");
713    dvmDumpJniReferenceTables();
714    // could dump thread's internalLocalRefTable, probably not useful
715    // ditto for thread's jniMonitorRefTable
716    ALOGI("---");
717    RETURN_VOID();
718}
719
720/*
721 * static void crash()
722 *
723 * Dump the current thread's interpreted stack and abort the VM.  Useful
724 * for seeing both interpreted and native stack traces.
725 *
726 * (Might want to restrict this to debuggable processes as a security
727 * measure, or check SecurityManager.checkExit().)
728 */
729static void Dalvik_dalvik_system_VMDebug_crash(const u4* args,
730    JValue* pResult)
731{
732    UNUSED_PARAMETER(args);
733    UNUSED_PARAMETER(pResult);
734
735    ALOGW("Crashing VM on request");
736    dvmDumpThread(dvmThreadSelf(), false);
737    dvmAbort();
738}
739
740/*
741 * static void infopoint(int id)
742 *
743 * Provide a hook for gdb to hang to so that the VM can be stopped when
744 * user-tagged source locations are being executed.
745 */
746static void Dalvik_dalvik_system_VMDebug_infopoint(const u4* args,
747    JValue* pResult)
748{
749    gDvm.nativeDebuggerActive = true;
750
751    ALOGD("VMDebug infopoint %d hit", args[0]);
752
753    gDvm.nativeDebuggerActive = false;
754    RETURN_VOID();
755}
756
757static void Dalvik_dalvik_system_VMDebug_countInstancesOfClass(const u4* args,
758    JValue* pResult)
759{
760    ClassObject* clazz = (ClassObject*)args[0];
761    bool countAssignable = args[1];
762    if (clazz == NULL) {
763        RETURN_LONG(0);
764    }
765    if (countAssignable) {
766        size_t count = dvmCountAssignableInstancesOfClass(clazz);
767        RETURN_LONG((long long)count);
768    } else {
769        size_t count = dvmCountInstancesOfClass(clazz);
770        RETURN_LONG((long long)count);
771    }
772}
773
774/*
775 * public static native void getHeapSpaceStats(long[] data)
776 */
777static void Dalvik_dalvik_system_VMDebug_getHeapSpaceStats(const u4* args,
778    JValue* pResult)
779{
780    ArrayObject* dataArray = (ArrayObject*) args[0];
781
782    if (dataArray == NULL || dataArray->length < 6) {
783      RETURN_VOID();
784    }
785
786    jlong* arr = (jlong*)(void*)dataArray->contents;
787
788    int j = 0;
789    size_t per_heap_allocated[2];
790    size_t per_heap_size[2];
791    memset(per_heap_allocated, 0, sizeof(per_heap_allocated));
792    memset(per_heap_size, 0, sizeof(per_heap_size));
793    dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, (size_t*) &per_heap_allocated, 2);
794    dvmHeapSourceGetValue(HS_FOOTPRINT, (size_t*) &per_heap_size, 2);
795    jlong heapSize = per_heap_size[0];
796    jlong heapUsed = per_heap_allocated[0];
797    jlong heapFree = heapSize - heapUsed;
798    jlong zygoteSize = per_heap_size[1];
799    jlong zygoteUsed = per_heap_allocated[1];
800    jlong zygoteFree = zygoteSize - zygoteUsed;
801    arr[j++] = heapSize;
802    arr[j++] = heapUsed;
803    arr[j++] = heapFree;
804    arr[j++] = zygoteSize;
805    arr[j++] = zygoteUsed;
806    arr[j++] = zygoteFree;
807
808    RETURN_VOID();
809}
810
811const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = {
812    { "getVmFeatureList",           "()[Ljava/lang/String;",
813        Dalvik_dalvik_system_VMDebug_getVmFeatureList },
814    { "getAllocCount",              "(I)I",
815        Dalvik_dalvik_system_VMDebug_getAllocCount },
816    { "getHeapSpaceStats",          "([J)V",
817        Dalvik_dalvik_system_VMDebug_getHeapSpaceStats },
818    { "resetAllocCount",            "(I)V",
819        Dalvik_dalvik_system_VMDebug_resetAllocCount },
820    { "startAllocCounting",         "()V",
821        Dalvik_dalvik_system_VMDebug_startAllocCounting },
822    { "stopAllocCounting",          "()V",
823        Dalvik_dalvik_system_VMDebug_stopAllocCounting },
824    { "startMethodTracingDdmsImpl", "(IIZI)V",
825        Dalvik_dalvik_system_VMDebug_startMethodTracingDdmsImpl },
826    { "startMethodTracingFd",       "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V",
827        Dalvik_dalvik_system_VMDebug_startMethodTracingFd },
828    { "startMethodTracingFilename", "(Ljava/lang/String;II)V",
829        Dalvik_dalvik_system_VMDebug_startMethodTracingFilename },
830    { "getMethodTracingMode",       "()I",
831        Dalvik_dalvik_system_VMDebug_getMethodTracingMode },
832    { "stopMethodTracing",          "()V",
833        Dalvik_dalvik_system_VMDebug_stopMethodTracing },
834    { "startEmulatorTracing",       "()V",
835        Dalvik_dalvik_system_VMDebug_startEmulatorTracing },
836    { "stopEmulatorTracing",        "()V",
837        Dalvik_dalvik_system_VMDebug_stopEmulatorTracing },
838    { "startInstructionCounting",   "()V",
839        Dalvik_dalvik_system_VMDebug_startInstructionCounting },
840    { "stopInstructionCounting",    "()V",
841        Dalvik_dalvik_system_VMDebug_stopInstructionCounting },
842    { "resetInstructionCount",      "()V",
843        Dalvik_dalvik_system_VMDebug_resetInstructionCount },
844    { "getInstructionCount",        "([I)V",
845        Dalvik_dalvik_system_VMDebug_getInstructionCount },
846    { "isDebuggerConnected",        "()Z",
847        Dalvik_dalvik_system_VMDebug_isDebuggerConnected },
848    { "isDebuggingEnabled",         "()Z",
849        Dalvik_dalvik_system_VMDebug_isDebuggingEnabled },
850    { "lastDebuggerActivity",       "()J",
851        Dalvik_dalvik_system_VMDebug_lastDebuggerActivity },
852    { "printLoadedClasses",         "(I)V",
853        Dalvik_dalvik_system_VMDebug_printLoadedClasses },
854    { "getLoadedClassCount",        "()I",
855        Dalvik_dalvik_system_VMDebug_getLoadedClassCount },
856    { "threadCpuTimeNanos",         "()J",
857        Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
858    { "dumpHprofData",              "(Ljava/lang/String;Ljava/io/FileDescriptor;)V",
859        Dalvik_dalvik_system_VMDebug_dumpHprofData },
860    { "dumpHprofDataDdms",          "()V",
861        Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms },
862    { "cacheRegisterMap",           "(Ljava/lang/String;)Z",
863        Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
864    { "dumpReferenceTables",        "()V",
865        Dalvik_dalvik_system_VMDebug_dumpReferenceTables },
866    { "crash",                      "()V",
867        Dalvik_dalvik_system_VMDebug_crash },
868    { "infopoint",                 "(I)V",
869        Dalvik_dalvik_system_VMDebug_infopoint },
870    { "countInstancesOfClass",     "(Ljava/lang/Class;Z)J",
871        Dalvik_dalvik_system_VMDebug_countInstancesOfClass },
872    { NULL, NULL, NULL },
873};
874