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