1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.L; 4 import static android.os.Build.VERSION_CODES.M; 5 6 import android.os.Debug; 7 import com.google.common.collect.ImmutableMap; 8 import com.google.common.io.Files; 9 import java.io.File; 10 import java.io.IOException; 11 import java.nio.charset.Charset; 12 import java.util.Map; 13 import org.robolectric.RuntimeEnvironment; 14 import org.robolectric.annotation.Implementation; 15 import org.robolectric.annotation.Implements; 16 import org.robolectric.annotation.Resetter; 17 18 @Implements(Debug.class) 19 public class ShadowDebug { 20 21 private static boolean tracingStarted = false; 22 private static String tracingFilename; 23 24 @Implementation __staticInitializer__()25 protected static void __staticInitializer__() { 26 // Avoid calling Environment.getLegacyExternalStorageDirectory() 27 } 28 29 @Implementation getNativeHeapAllocatedSize()30 protected static long getNativeHeapAllocatedSize() { 31 return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); 32 } 33 34 @Implementation(minSdk = M) getRuntimeStats()35 protected static Map<String, String> getRuntimeStats() { 36 return ImmutableMap.<String, String>builder().build(); 37 } 38 39 @Implementation startMethodTracing()40 protected static void startMethodTracing() { 41 internalStartTracing(fixTracePath(null)); 42 } 43 44 @Implementation startMethodTracing(String tracePath, int bufferSize, int flags)45 protected static void startMethodTracing(String tracePath, int bufferSize, int flags) { 46 internalStartTracing(fixTracePath(tracePath)); 47 } 48 49 @Implementation startMethodTracing(String tracePath)50 protected static void startMethodTracing(String tracePath) { 51 internalStartTracing(fixTracePath(tracePath)); 52 } 53 54 @Implementation startMethodTracing(String tracePath, int bufferSize)55 protected static void startMethodTracing(String tracePath, int bufferSize) { 56 internalStartTracing(fixTracePath(tracePath)); 57 } 58 59 @Implementation(minSdk = L) startMethodTracingSampling(String tracePath, int bufferSize, int intervalUs)60 protected static void startMethodTracingSampling(String tracePath, int bufferSize, int intervalUs) { 61 internalStartTracing(fixTracePath(tracePath)); 62 } 63 64 @Implementation stopMethodTracing()65 protected static void stopMethodTracing() { 66 if (!tracingStarted) { 67 throw new RuntimeException("Tracing is not started."); 68 } 69 70 try { 71 Files.asCharSink(new File(tracingFilename), Charset.forName("UTF-8")).write("trace data"); 72 } catch (IOException e) { 73 throw new RuntimeException("Writing trace file failed", e); 74 } 75 tracingStarted = false; 76 tracingFilename = null; 77 } 78 internalStartTracing(String tracePath)79 private static void internalStartTracing(String tracePath) { 80 if (tracingStarted) { 81 throw new RuntimeException("Tracing is already started."); 82 } 83 tracingStarted = true; 84 tracingFilename = tracePath; 85 } 86 87 @Resetter reset()88 public static void reset() { 89 tracingStarted = false; 90 tracingFilename = null; 91 } 92 93 // Forked from android.os.Debug fixTracePath(String tracePath)94 private static String fixTracePath(String tracePath) { 95 String defaultTraceBody = "dmtrace"; 96 String defaultTraceExtension = ".trace"; 97 98 if (tracePath == null || tracePath.charAt(0) != '/') { 99 final File dir = RuntimeEnvironment.application.getExternalFilesDir(null); 100 if (tracePath == null) { 101 tracePath = new File(dir, defaultTraceBody).getAbsolutePath(); 102 } else { 103 tracePath = new File(dir, tracePath).getAbsolutePath(); 104 } 105 } 106 if (!tracePath.endsWith(defaultTraceExtension)) { 107 tracePath += defaultTraceExtension; 108 } 109 return tracePath; 110 } 111 } 112