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