Merge change 24060 into eclair
* changes: Integrated the profiler into the framework. We run it all the time if the persist.sampling_profiler system property is set. Saves snapshots to the SD card.
This commit is contained in:
@@ -68,6 +68,7 @@ import android.view.WindowManagerImpl;
|
|||||||
|
|
||||||
import com.android.internal.os.BinderInternal;
|
import com.android.internal.os.BinderInternal;
|
||||||
import com.android.internal.os.RuntimeInit;
|
import com.android.internal.os.RuntimeInit;
|
||||||
|
import com.android.internal.os.SamplingProfilerIntegration;
|
||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
|
|
||||||
import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
|
import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
|
||||||
@@ -87,6 +88,8 @@ import java.util.Map;
|
|||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import dalvik.system.SamplingProfiler;
|
||||||
|
|
||||||
final class IntentReceiverLeaked extends AndroidRuntimeException {
|
final class IntentReceiverLeaked extends AndroidRuntimeException {
|
||||||
public IntentReceiverLeaked(String msg) {
|
public IntentReceiverLeaked(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
@@ -1727,6 +1730,10 @@ public final class ActivityThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class H extends Handler {
|
private final class H extends Handler {
|
||||||
|
private H() {
|
||||||
|
SamplingProfiler.getInstance().setEventThread(mLooper.getThread());
|
||||||
|
}
|
||||||
|
|
||||||
public static final int LAUNCH_ACTIVITY = 100;
|
public static final int LAUNCH_ACTIVITY = 100;
|
||||||
public static final int PAUSE_ACTIVITY = 101;
|
public static final int PAUSE_ACTIVITY = 101;
|
||||||
public static final int PAUSE_ACTIVITY_FINISHING= 102;
|
public static final int PAUSE_ACTIVITY_FINISHING= 102;
|
||||||
@@ -1811,6 +1818,7 @@ public final class ActivityThread {
|
|||||||
} break;
|
} break;
|
||||||
case PAUSE_ACTIVITY:
|
case PAUSE_ACTIVITY:
|
||||||
handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
|
handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
|
||||||
|
maybeSnapshot();
|
||||||
break;
|
break;
|
||||||
case PAUSE_ACTIVITY_FINISHING:
|
case PAUSE_ACTIVITY_FINISHING:
|
||||||
handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2);
|
handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2);
|
||||||
@@ -1853,6 +1861,7 @@ public final class ActivityThread {
|
|||||||
break;
|
break;
|
||||||
case RECEIVER:
|
case RECEIVER:
|
||||||
handleReceiver((ReceiverData)msg.obj);
|
handleReceiver((ReceiverData)msg.obj);
|
||||||
|
maybeSnapshot();
|
||||||
break;
|
break;
|
||||||
case CREATE_SERVICE:
|
case CREATE_SERVICE:
|
||||||
handleCreateService((CreateServiceData)msg.obj);
|
handleCreateService((CreateServiceData)msg.obj);
|
||||||
@@ -1868,6 +1877,7 @@ public final class ActivityThread {
|
|||||||
break;
|
break;
|
||||||
case STOP_SERVICE:
|
case STOP_SERVICE:
|
||||||
handleStopService((IBinder)msg.obj);
|
handleStopService((IBinder)msg.obj);
|
||||||
|
maybeSnapshot();
|
||||||
break;
|
break;
|
||||||
case REQUEST_THUMBNAIL:
|
case REQUEST_THUMBNAIL:
|
||||||
handleRequestThumbnail((IBinder)msg.obj);
|
handleRequestThumbnail((IBinder)msg.obj);
|
||||||
@@ -1907,6 +1917,13 @@ public final class ActivityThread {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void maybeSnapshot() {
|
||||||
|
if (mBoundApplication != null) {
|
||||||
|
SamplingProfilerIntegration.writeSnapshot(
|
||||||
|
mBoundApplication.processName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class Idler implements MessageQueue.IdleHandler {
|
private final class Idler implements MessageQueue.IdleHandler {
|
||||||
@@ -4213,6 +4230,8 @@ public final class ActivityThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final void main(String[] args) {
|
public static final void main(String[] args) {
|
||||||
|
SamplingProfilerIntegration.start();
|
||||||
|
|
||||||
Process.setArgV0("<pre-initialized>");
|
Process.setArgV0("<pre-initialized>");
|
||||||
|
|
||||||
Looper.prepareMainLooper();
|
Looper.prepareMainLooper();
|
||||||
@@ -4228,8 +4247,11 @@ public final class ActivityThread {
|
|||||||
|
|
||||||
thread.detach();
|
thread.detach();
|
||||||
String name;
|
String name;
|
||||||
if (thread.mInitialApplication != null) name = thread.mInitialApplication.getPackageName();
|
if (thread.mInitialApplication != null) {
|
||||||
else name = "<unknown>";
|
name = thread.mInitialApplication.getPackageName();
|
||||||
|
} else {
|
||||||
|
name = "<unknown>";
|
||||||
|
}
|
||||||
Log.i(TAG, "Main thread of " + name + " is now exiting");
|
Log.i(TAG, "Main thread of " + name + " is now exiting");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package com.android.internal.os;
|
||||||
|
|
||||||
|
import dalvik.system.SamplingProfiler;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.os.*;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integrates the framework with Dalvik's sampling profiler.
|
||||||
|
*/
|
||||||
|
public class SamplingProfilerIntegration {
|
||||||
|
|
||||||
|
private static final String TAG = "SamplingProfilerIntegration";
|
||||||
|
|
||||||
|
private static final boolean enabled;
|
||||||
|
private static final Executor snapshotWriter;
|
||||||
|
static {
|
||||||
|
enabled = "1".equals(SystemProperties.get("persist.sampling_profiler"));
|
||||||
|
if (enabled) {
|
||||||
|
snapshotWriter = Executors.newSingleThreadExecutor();
|
||||||
|
Log.i(TAG, "Profiler is enabled.");
|
||||||
|
} else {
|
||||||
|
snapshotWriter = null;
|
||||||
|
Log.i(TAG, "Profiler is disabled.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is profiling enabled?
|
||||||
|
*/
|
||||||
|
public static boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the profiler if profiling is enabled.
|
||||||
|
*/
|
||||||
|
public static void start() {
|
||||||
|
if (!enabled) return;
|
||||||
|
SamplingProfiler.getInstance().start(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether or not we've created the snapshots dir. */
|
||||||
|
static boolean dirMade = false;
|
||||||
|
|
||||||
|
/** Whether or not a snapshot is being persisted. */
|
||||||
|
static volatile boolean pending;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a snapshot to the SD card if profiling is enabled.
|
||||||
|
*/
|
||||||
|
public static void writeSnapshot(final String name) {
|
||||||
|
if (!enabled) return;
|
||||||
|
|
||||||
|
if (!pending) {
|
||||||
|
pending = true;
|
||||||
|
snapshotWriter.execute(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
String dir = "/sdcard/snapshots";
|
||||||
|
if (!dirMade) {
|
||||||
|
makeDirectory(dir);
|
||||||
|
dirMade = true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
writeSnapshot(dir, name);
|
||||||
|
} finally {
|
||||||
|
pending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the zygote's snapshot to internal storage if profiling is enabled.
|
||||||
|
*/
|
||||||
|
public static void writeZygoteSnapshot() {
|
||||||
|
if (!enabled) return;
|
||||||
|
|
||||||
|
String dir = "/data/zygote/snapshots";
|
||||||
|
makeDirectory(dir);
|
||||||
|
writeSnapshot(dir, "zygote");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeSnapshot(String dir, String name) {
|
||||||
|
byte[] snapshot = SamplingProfiler.getInstance().snapshot();
|
||||||
|
if (snapshot == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use the current time as a unique ID. We can't use a counter
|
||||||
|
* because processes restart. This could result in some overlap if
|
||||||
|
* we capture two snapshots in rapid succession.
|
||||||
|
*/
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
String path = dir + "/" + name.replace(':', '.') + "-"
|
||||||
|
+ System.currentTimeMillis() + ".snapshot";
|
||||||
|
try {
|
||||||
|
// Try to open the file a few times. The SD card may not be mounted.
|
||||||
|
FileOutputStream out;
|
||||||
|
int count = 0;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
out = new FileOutputStream(path);
|
||||||
|
break;
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
if (++count > 3) {
|
||||||
|
Log.e(TAG, "Could not open " + path + ".");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sleep for a bit and then try again.
|
||||||
|
try {
|
||||||
|
Thread.sleep(2500);
|
||||||
|
} catch (InterruptedException e1) { /* ignore */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
out.write(snapshot);
|
||||||
|
} finally {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
long elapsed = System.currentTimeMillis() - start;
|
||||||
|
Log.i(TAG, "Wrote snapshot for " + name
|
||||||
|
+ " in " + elapsed + "ms.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Error writing snapshot.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void makeDirectory(String dir) {
|
||||||
|
new File(dir).mkdirs();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,6 @@ package com.android.internal.os;
|
|||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.LocalServerSocket;
|
import android.net.LocalServerSocket;
|
||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
@@ -31,6 +30,7 @@ import android.util.Log;
|
|||||||
|
|
||||||
import dalvik.system.VMRuntime;
|
import dalvik.system.VMRuntime;
|
||||||
import dalvik.system.Zygote;
|
import dalvik.system.Zygote;
|
||||||
|
import dalvik.system.SamplingProfiler;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
@@ -573,6 +573,9 @@ public class ZygoteInit {
|
|||||||
|
|
||||||
public static void main(String argv[]) {
|
public static void main(String argv[]) {
|
||||||
try {
|
try {
|
||||||
|
// Start profiling the zygote initialization.
|
||||||
|
SamplingProfilerIntegration.start();
|
||||||
|
|
||||||
registerZygoteSocket();
|
registerZygoteSocket();
|
||||||
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
|
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
|
||||||
SystemClock.uptimeMillis());
|
SystemClock.uptimeMillis());
|
||||||
@@ -582,6 +585,13 @@ public class ZygoteInit {
|
|||||||
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
|
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
|
||||||
SystemClock.uptimeMillis());
|
SystemClock.uptimeMillis());
|
||||||
|
|
||||||
|
if (SamplingProfilerIntegration.isEnabled()) {
|
||||||
|
SamplingProfiler sp = SamplingProfiler.getInstance();
|
||||||
|
sp.pause();
|
||||||
|
SamplingProfilerIntegration.writeZygoteSnapshot();
|
||||||
|
sp.shutDown();
|
||||||
|
}
|
||||||
|
|
||||||
// Do an initial gc to clean up after startup
|
// Do an initial gc to clean up after startup
|
||||||
gc();
|
gc();
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.server;
|
|||||||
|
|
||||||
import com.android.server.am.ActivityManagerService;
|
import com.android.server.am.ActivityManagerService;
|
||||||
import com.android.server.status.StatusBarService;
|
import com.android.server.status.StatusBarService;
|
||||||
|
import com.android.internal.os.SamplingProfilerIntegration;
|
||||||
|
|
||||||
import dalvik.system.VMRuntime;
|
import dalvik.system.VMRuntime;
|
||||||
|
|
||||||
@@ -41,6 +42,9 @@ import android.util.EventLog;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.accounts.AccountManagerService;
|
import android.accounts.AccountManagerService;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
class ServerThread extends Thread {
|
class ServerThread extends Thread {
|
||||||
private static final String TAG = "SystemServer";
|
private static final String TAG = "SystemServer";
|
||||||
private final static boolean INCLUDE_DEMO = false;
|
private final static boolean INCLUDE_DEMO = false;
|
||||||
@@ -452,6 +456,9 @@ public class SystemServer
|
|||||||
public static final int FACTORY_TEST_LOW_LEVEL = 1;
|
public static final int FACTORY_TEST_LOW_LEVEL = 1;
|
||||||
public static final int FACTORY_TEST_HIGH_LEVEL = 2;
|
public static final int FACTORY_TEST_HIGH_LEVEL = 2;
|
||||||
|
|
||||||
|
static Timer timer;
|
||||||
|
static final long SNAPSHOT_INTERVAL = 60 * 60 * 1000; // 1hr
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from Zygote to initialize the system. This will cause the native
|
* This method is called from Zygote to initialize the system. This will cause the native
|
||||||
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
|
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
|
||||||
@@ -460,6 +467,17 @@ public class SystemServer
|
|||||||
native public static void init1(String[] args);
|
native public static void init1(String[] args);
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
if (SamplingProfilerIntegration.isEnabled()) {
|
||||||
|
SamplingProfilerIntegration.start();
|
||||||
|
timer = new Timer();
|
||||||
|
timer.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
SamplingProfilerIntegration.writeSnapshot("system_server");
|
||||||
|
}
|
||||||
|
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
// The system server has to run all of the time, so it needs to be
|
// The system server has to run all of the time, so it needs to be
|
||||||
// as efficient as possible with its memory usage.
|
// as efficient as possible with its memory usage.
|
||||||
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
|
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
|
||||||
|
|||||||
Reference in New Issue
Block a user