SamplingProfilerIntegration.java revision e540833fdff4d58e37c9ba859388e24e2945ed45
1package com.android.internal.os; 2 3import dalvik.system.SamplingProfiler; 4 5import java.io.File; 6import java.io.FileOutputStream; 7import java.io.IOException; 8import java.io.FileNotFoundException; 9import java.util.concurrent.Executor; 10import java.util.concurrent.Executors; 11 12import android.util.Log; 13import android.os.*; 14import android.net.Uri; 15 16/** 17 * Integrates the framework with Dalvik's sampling profiler. 18 */ 19public class SamplingProfilerIntegration { 20 21 private static final String TAG = "SamplingProfilerIntegration"; 22 23 private static final boolean enabled; 24 private static final Executor snapshotWriter; 25 static { 26 enabled = "1".equals(SystemProperties.get("persist.sampling_profiler")); 27 if (enabled) { 28 snapshotWriter = Executors.newSingleThreadExecutor(); 29 Log.i(TAG, "Profiler is enabled."); 30 } else { 31 snapshotWriter = null; 32 Log.i(TAG, "Profiler is disabled."); 33 } 34 } 35 36 /** 37 * Is profiling enabled? 38 */ 39 public static boolean isEnabled() { 40 return enabled; 41 } 42 43 /** 44 * Starts the profiler if profiling is enabled. 45 */ 46 public static void start() { 47 if (!enabled) return; 48 SamplingProfiler.getInstance().start(10); 49 } 50 51 /** Whether or not we've created the snapshots dir. */ 52 static boolean dirMade = false; 53 54 /** Whether or not a snapshot is being persisted. */ 55 static volatile boolean pending; 56 57 /** 58 * Writes a snapshot to the SD card if profiling is enabled. 59 */ 60 public static void writeSnapshot(final String name) { 61 if (!enabled) return; 62 63 if (!pending) { 64 pending = true; 65 snapshotWriter.execute(new Runnable() { 66 public void run() { 67 String dir = "/sdcard/snapshots"; 68 if (!dirMade) { 69 makeDirectory(dir); 70 dirMade = true; 71 } 72 try { 73 writeSnapshot(dir, name); 74 } finally { 75 pending = false; 76 } 77 } 78 }); 79 } 80 } 81 82 /** 83 * Writes the zygote's snapshot to internal storage if profiling is enabled. 84 */ 85 public static void writeZygoteSnapshot() { 86 if (!enabled) return; 87 88 String dir = "/data/zygote/snapshots"; 89 makeDirectory(dir); 90 writeSnapshot(dir, "zygote"); 91 } 92 93 private static void writeSnapshot(String dir, String name) { 94 byte[] snapshot = SamplingProfiler.getInstance().snapshot(); 95 if (snapshot == null) { 96 return; 97 } 98 99 /* 100 * We use the current time as a unique ID. We can't use a counter 101 * because processes restart. This could result in some overlap if 102 * we capture two snapshots in rapid succession. 103 */ 104 long start = System.currentTimeMillis(); 105 String path = dir + "/" + name.replace(':', '.') + "-" 106 + System.currentTimeMillis() + ".snapshot"; 107 try { 108 // Try to open the file a few times. The SD card may not be mounted. 109 FileOutputStream out; 110 int count = 0; 111 while (true) { 112 try { 113 out = new FileOutputStream(path); 114 break; 115 } catch (FileNotFoundException e) { 116 if (++count > 3) { 117 Log.e(TAG, "Could not open " + path + "."); 118 return; 119 } 120 121 // Sleep for a bit and then try again. 122 try { 123 Thread.sleep(2500); 124 } catch (InterruptedException e1) { /* ignore */ } 125 } 126 } 127 128 try { 129 out.write(snapshot); 130 } finally { 131 out.close(); 132 } 133 long elapsed = System.currentTimeMillis() - start; 134 Log.i(TAG, "Wrote snapshot for " + name 135 + " in " + elapsed + "ms."); 136 } catch (IOException e) { 137 Log.e(TAG, "Error writing snapshot.", e); 138 } 139 } 140 141 private static void makeDirectory(String dir) { 142 new File(dir).mkdirs(); 143 } 144} 145