1 /*
2  * Copyright (C) 2009 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 package android.os.cts;
17 
18 import android.content.Context;
19 import android.os.Debug;
20 import android.platform.test.annotations.AppModeFull;
21 import android.test.AndroidTestCase;
22 
23 import com.android.compatibility.common.util.TestThread;
24 
25 import java.io.File;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.logging.Level;
32 import java.util.logging.Logger;
33 
34 public class DebugTest extends AndroidTestCase {
35     private static final Logger Log = Logger.getLogger(DebugTest.class.getName());
36 
37     // Static list here to avoid R8 optimizations in #testGetAndReset causing wrong alloc counts
38     private static final List<int[]> TEST_ALLOC = new ArrayList<>();
39 
40     @Override
tearDown()41     public void tearDown() throws Exception {
42         super.tearDown();
43         Debug.stopAllocCounting();
44         Debug.resetAllCounts();
45     }
46 
testPrintLoadedClasses()47     public void testPrintLoadedClasses() {
48         Debug.printLoadedClasses(Debug.SHOW_FULL_DETAIL);
49         Debug.printLoadedClasses(Debug.SHOW_CLASSLOADER);
50         Debug.printLoadedClasses(Debug.SHOW_INITIALIZED);
51     }
52 
testStartMethodTracing()53     public void testStartMethodTracing() throws InterruptedException {
54         final long debugTime = 3000;
55         final String traceName = getFileName();
56 
57         final int bufSize = 1024 * 1024 * 2;
58         final int debug_flag = Debug.TRACE_COUNT_ALLOCS;
59 
60         Debug.startMethodTracing(traceName);
61         Thread.sleep(debugTime);
62         Debug.stopMethodTracing();
63 
64         Debug.startMethodTracing(traceName, bufSize);
65         Thread.sleep(debugTime);
66         Debug.stopMethodTracing();
67 
68         Debug.startMethodTracing(traceName, bufSize, debug_flag);
69         Thread.sleep(debugTime);
70         Debug.stopMethodTracing();
71     }
72 
73     @AppModeFull(
74             reason = "Default trace in Context#getExternalFilesDir not accessible by instant apps"
75     )
testStartMethodTracingDefaultExternalStorage()76     public void testStartMethodTracingDefaultExternalStorage() throws InterruptedException {
77         final long debugTime = 3000;
78 
79         Debug.startMethodTracing();
80         Thread.sleep(debugTime);
81         Debug.stopMethodTracing();
82     }
83 
getFileName()84     private String getFileName() {
85         File dir = getContext().getFilesDir();
86         File file = new File(dir, "debug.trace");
87         return file.getAbsolutePath();
88     }
89 
testStartNativeTracing()90     public void testStartNativeTracing() {
91         Debug.startNativeTracing();
92 
93         Debug.stopNativeTracing();
94     }
95 
testThreadCpuTimeNanos()96     public void testThreadCpuTimeNanos() throws Exception {
97         if (Debug.threadCpuTimeNanos() == -1) {
98             // Indicates the system does not support this operation, so we can't test it.
99             Log.log(Level.WARNING, "Skipping testThreadCpuTimeNanos() on unsupported system");
100             return;
101         }
102 
103         TestThread t = new TestThread(new Runnable() {
104                 @Override
105                 public void run() {
106                     long startDebugTime = Debug.threadCpuTimeNanos();
107 
108                     // Do some work for a second to increment CPU time
109                     long startSystemTime = System.currentTimeMillis();
110                     while (System.currentTimeMillis() - startSystemTime < 1000) {
111                         Math.random();
112                     }
113 
114                     // Verify that threadCpuTimeNanos reports that some work was done.
115                     // We can't do more than this because the specification for this API call makes
116                     // clear that this is only an estimate.
117                     assertTrue(Debug.threadCpuTimeNanos() > startDebugTime);
118                 }
119             });
120         t.start();
121         t.join();
122     }
123 
testWaitingForDebugger()124     public void testWaitingForDebugger() {
125         assertFalse(Debug.waitingForDebugger());
126     }
127 
testGetAndReset()128     public void testGetAndReset() throws IOException {
129         final String dumpFile = getFileName();
130         Debug.startAllocCounting();
131 
132         final int MIN_GLOBAL_ALLOC_COUNT = 100;
133         final int ARRAY_SIZE = 100;
134         final int MIN_GLOBAL_ALLOC_SIZE = MIN_GLOBAL_ALLOC_COUNT * ARRAY_SIZE;
135         for(int i = 0; i < MIN_GLOBAL_ALLOC_COUNT; i++){
136             // for test alloc huge memory
137             TEST_ALLOC.add(new int[ARRAY_SIZE]);
138             TEST_ALLOC.clear();
139         }
140 
141         assertTrue(Debug.getGlobalAllocCount() >= MIN_GLOBAL_ALLOC_COUNT);
142         assertTrue(Debug.getGlobalAllocSize() >= MIN_GLOBAL_ALLOC_SIZE);
143         assertTrue(Debug.getGlobalFreedCount() >= 0);
144         assertTrue(Debug.getGlobalFreedSize() >= 0);
145         assertTrue(Debug.getNativeHeapSize() >= 0);
146         assertTrue(Debug.getGlobalExternalAllocCount() >= 0);
147         assertTrue(Debug.getGlobalExternalAllocSize() >= 0);
148         assertTrue(Debug.getGlobalExternalFreedCount() >= 0);
149         assertTrue(Debug.getGlobalExternalFreedSize() >= 0);
150         assertTrue(Debug.getLoadedClassCount() >= 0);
151         assertTrue(Debug.getNativeHeapAllocatedSize() >= 0);
152         assertTrue(Debug.getNativeHeapFreeSize() >= 0);
153         assertTrue(Debug.getNativeHeapSize() >= 0);
154         assertTrue(Debug.getThreadAllocCount() >= 0);
155         assertTrue(Debug.getThreadAllocSize() >= 0);
156         assertTrue(Debug.getThreadExternalAllocCount() >=0);
157         assertTrue(Debug.getThreadExternalAllocSize() >= 0);
158         assertTrue(Debug.getThreadGcInvocationCount() >= 0);
159         assertTrue(Debug.getBinderDeathObjectCount() >= 0);
160         assertTrue(Debug.getBinderLocalObjectCount() >= 0);
161         assertTrue(Debug.getBinderProxyObjectCount() >= 0);
162         Debug.getBinderReceivedTransactions();
163         Debug.getBinderSentTransactions();
164 
165         Debug.stopAllocCounting();
166 
167         Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
168         Debug.getMemoryInfo(memoryInfo);
169 
170         Debug.resetGlobalAllocCount();
171         assertEquals(0, Debug.getGlobalAllocCount());
172 
173         Debug.resetGlobalAllocSize();
174         assertEquals(0, Debug.getGlobalAllocSize());
175 
176         Debug.resetGlobalExternalAllocCount();
177         assertEquals(0, Debug.getGlobalExternalAllocCount());
178 
179         Debug.resetGlobalExternalAllocSize();
180         assertEquals(0, Debug.getGlobalExternalAllocSize());
181 
182         Debug.resetGlobalExternalFreedCount();
183         assertEquals(0, Debug.getGlobalExternalFreedCount());
184 
185         Debug.resetGlobalExternalFreedSize();
186         assertEquals(0, Debug.getGlobalExternalFreedSize());
187 
188         Debug.resetGlobalFreedCount();
189         assertEquals(0, Debug.getGlobalFreedCount());
190 
191         Debug.resetGlobalFreedSize();
192         assertEquals(0, Debug.getGlobalFreedSize());
193 
194         Debug.resetGlobalGcInvocationCount();
195         assertEquals(0, Debug.getGlobalGcInvocationCount());
196 
197         Debug.resetThreadAllocCount();
198         assertEquals(0, Debug.getThreadAllocCount());
199 
200         Debug.resetThreadAllocSize();
201         assertEquals(0, Debug.getThreadAllocSize());
202 
203         Debug.resetThreadExternalAllocCount();
204         assertEquals(0, Debug.getThreadExternalAllocCount());
205 
206         Debug.resetThreadExternalAllocSize();
207         assertEquals(0, Debug.getThreadExternalAllocSize());
208 
209         Debug.resetThreadGcInvocationCount();
210         assertEquals(0, Debug.getThreadGcInvocationCount());
211 
212         Debug.resetAllCounts();
213         Debug.dumpHprofData(dumpFile);
214     }
215 
testDumpService()216     public void testDumpService() throws Exception {
217         File file = getContext().getFileStreamPath("dump.out");
218         file.delete();
219         assertFalse(file.exists());
220 
221         FileOutputStream out = getContext().openFileOutput("dump.out", Context.MODE_PRIVATE);
222         assertFalse(Debug.dumpService("xyzzy -- not a valid service name", out.getFD(), null));
223         out.close();
224 
225         // File was opened, but nothing was written
226         assertTrue(file.exists());
227         assertEquals(0, file.length());
228 
229         out = getContext().openFileOutput("dump.out", Context.MODE_PRIVATE);
230         assertTrue(Debug.dumpService(Context.POWER_SERVICE, out.getFD(), null));
231         out.close();
232 
233         // Don't require any specific content, just that something was written
234         assertTrue(file.exists());
235         assertTrue(file.length() > 0);
236     }
237 
checkNumber(String s)238     private static void checkNumber(String s) throws Exception {
239         assertTrue(s != null);
240         long n = Long.valueOf(s);
241         assertTrue(n >= 0);
242     }
243 
checkHistogram(String s)244     private static void checkHistogram(String s) throws Exception {
245         assertTrue(s != null);
246         assertTrue(s.length() > 0);
247         String[] buckets = s.split(",");
248         long last_key = 0;
249         for (int i = 0; i < buckets.length; ++i) {
250             String bucket = buckets[i];
251             assertTrue(bucket.length() > 0);
252             String[] kv = bucket.split(":");
253             assertTrue(kv.length == 2);
254             assertTrue(kv[0].length() > 0);
255             assertTrue(kv[1].length() > 0);
256             long key = Long.valueOf(kv[0]);
257             long value = Long.valueOf(kv[1]);
258             assertTrue(key >= 0);
259             assertTrue(value >= 0);
260             assertTrue(key >= last_key);
261             last_key = key;
262         }
263     }
264 
testGetRuntimeStat()265     public void testGetRuntimeStat() throws Exception {
266         // Invoke at least one GC and wait for 20 seconds or so so we get at
267         // least one bucket in the histograms.
268         for (int i = 0; i < 20; ++i) {
269             Runtime.getRuntime().gc();
270             Thread.sleep(1000L);
271         }
272         String gc_count = Debug.getRuntimeStat("art.gc.gc-count");
273         String gc_time = Debug.getRuntimeStat("art.gc.gc-time");
274         String bytes_allocated = Debug.getRuntimeStat("art.gc.bytes-allocated");
275         String bytes_freed = Debug.getRuntimeStat("art.gc.bytes-freed");
276         String blocking_gc_count = Debug.getRuntimeStat("art.gc.blocking-gc-count");
277         String blocking_gc_time = Debug.getRuntimeStat("art.gc.blocking-gc-time");
278         String gc_count_rate_histogram = Debug.getRuntimeStat("art.gc.gc-count-rate-histogram");
279         String blocking_gc_count_rate_histogram =
280             Debug.getRuntimeStat("art.gc.blocking-gc-count-rate-histogram");
281         checkNumber(gc_count);
282         checkNumber(gc_time);
283         checkNumber(bytes_allocated);
284         checkNumber(bytes_freed);
285         checkNumber(blocking_gc_count);
286         checkNumber(blocking_gc_time);
287         checkHistogram(gc_count_rate_histogram);
288         checkHistogram(blocking_gc_count_rate_histogram);
289     }
290 
testGetRuntimeStats()291     public void testGetRuntimeStats() throws Exception {
292         // Invoke at least one GC and wait for 20 seconds or so so we get at
293         // least one bucket in the histograms.
294         for (int i = 0; i < 20; ++i) {
295             Runtime.getRuntime().gc();
296             Thread.sleep(1000L);
297         }
298         Map<String, String> map = Debug.getRuntimeStats();
299         String gc_count = map.get("art.gc.gc-count");
300         String gc_time = map.get("art.gc.gc-time");
301         String bytes_allocated = map.get("art.gc.bytes-allocated");
302         String bytes_freed = map.get("art.gc.bytes-freed");
303         String blocking_gc_count = map.get("art.gc.blocking-gc-count");
304         String blocking_gc_time = map.get("art.gc.blocking-gc-time");
305         String gc_count_rate_histogram = map.get("art.gc.gc-count-rate-histogram");
306         String blocking_gc_count_rate_histogram =
307             map.get("art.gc.blocking-gc-count-rate-histogram");
308         checkNumber(gc_count);
309         checkNumber(gc_time);
310         checkNumber(bytes_allocated);
311         checkNumber(bytes_freed);
312         checkNumber(blocking_gc_count);
313         checkNumber(blocking_gc_time);
314         checkHistogram(gc_count_rate_histogram);
315         checkHistogram(blocking_gc_count_rate_histogram);
316     }
317 
testGetMemoryStat()318     public void testGetMemoryStat() throws Exception {
319         Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
320         Debug.getMemoryInfo(memoryInfo);
321 
322         String summary_java_heap = memoryInfo.getMemoryStat("summary.java-heap");
323         String summary_native_heap = memoryInfo.getMemoryStat("summary.native-heap");
324         String summary_code = memoryInfo.getMemoryStat("summary.code");
325         String summary_stack = memoryInfo.getMemoryStat("summary.stack");
326         String summary_graphics = memoryInfo.getMemoryStat("summary.graphics");
327         String summary_private_other = memoryInfo.getMemoryStat("summary.private-other");
328         String summary_system = memoryInfo.getMemoryStat("summary.system");
329         String summary_total_pss = memoryInfo.getMemoryStat("summary.total-pss");
330         String summary_total_swap = memoryInfo.getMemoryStat("summary.total-swap");
331         checkNumber(summary_java_heap);
332         checkNumber(summary_native_heap);
333         checkNumber(summary_code);
334         checkNumber(summary_stack);
335         checkNumber(summary_graphics);
336         checkNumber(summary_private_other);
337         checkNumber(summary_system);
338         checkNumber(summary_total_pss);
339         checkNumber(summary_total_swap);
340     }
341 
testGetMemoryStats()342     public void testGetMemoryStats() throws Exception {
343         Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
344         Debug.getMemoryInfo(memoryInfo);
345 
346         Map<String, String> map = memoryInfo.getMemoryStats();
347         String summary_java_heap = map.get("summary.java-heap");
348         String summary_native_heap = map.get("summary.native-heap");
349         String summary_code = map.get("summary.code");
350         String summary_stack = map.get("summary.stack");
351         String summary_graphics = map.get("summary.graphics");
352         String summary_private_other = map.get("summary.private-other");
353         String summary_system = map.get("summary.system");
354         String summary_total_pss = map.get("summary.total-pss");
355         String summary_total_swap = map.get("summary.total-swap");
356         checkNumber(summary_java_heap);
357         checkNumber(summary_native_heap);
358         checkNumber(summary_code);
359         checkNumber(summary_stack);
360         checkNumber(summary_graphics);
361         checkNumber(summary_private_other);
362         checkNumber(summary_system);
363         checkNumber(summary_total_pss);
364         checkNumber(summary_total_swap);
365     }
366 }
367