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