1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.M; 4 import static android.os.Build.VERSION_CODES.N; 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 startMethodTracingSampling( String tracePath, int bufferSize, int intervalUs)60 protected static void startMethodTracingSampling( 61 String tracePath, int bufferSize, int intervalUs) { 62 internalStartTracing(fixTracePath(tracePath)); 63 } 64 65 @Implementation stopMethodTracing()66 protected static void stopMethodTracing() { 67 if (!tracingStarted) { 68 throw new RuntimeException("Tracing is not started."); 69 } 70 71 try { 72 Files.asCharSink(new File(tracingFilename), Charset.forName("UTF-8")).write("trace data"); 73 } catch (IOException e) { 74 throw new RuntimeException("Writing trace file failed", e); 75 } 76 tracingStarted = false; 77 tracingFilename = null; 78 } 79 internalStartTracing(String tracePath)80 private static void internalStartTracing(String tracePath) { 81 if (tracingStarted) { 82 throw new RuntimeException("Tracing is already started."); 83 } 84 tracingStarted = true; 85 tracingFilename = tracePath; 86 } 87 88 @Resetter reset()89 public static void reset() { 90 tracingStarted = false; 91 tracingFilename = null; 92 } 93 94 @Implementation(minSdk = N) fixTracePath(String tracePath)95 protected static String fixTracePath(String tracePath) { 96 String defaultTraceBody = "dmtrace"; 97 String defaultTraceExtension = ".trace"; 98 99 if (tracePath == null || tracePath.charAt(0) != '/') { 100 final File dir = RuntimeEnvironment.getApplication().getExternalFilesDir(null); 101 if (tracePath == null) { 102 tracePath = new File(dir, defaultTraceBody).getAbsolutePath(); 103 } else { 104 tracePath = new File(dir, tracePath).getAbsolutePath(); 105 } 106 } 107 if (!tracePath.endsWith(defaultTraceExtension)) { 108 tracePath += defaultTraceExtension; 109 } 110 return tracePath; 111 } 112 } 113