Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 88e62579 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

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.
parents a4eb91da e540833f
Loading
Loading
Loading
Loading
+120 −98
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import android.view.WindowManagerImpl;

import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.util.ArrayUtils;

import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
@@ -87,6 +88,8 @@ import java.util.Map;
import java.util.TimeZone;
import java.util.regex.Pattern;

import dalvik.system.SamplingProfiler;

final class IntentReceiverLeaked extends AndroidRuntimeException {
    public IntentReceiverLeaked(String msg) {
        super(msg);
@@ -1727,6 +1730,10 @@ public final class ActivityThread {
    }

    private final class H extends Handler {
        private H() {
            SamplingProfiler.getInstance().setEventThread(mLooper.getThread());
        }

        public static final int LAUNCH_ACTIVITY         = 100;
        public static final int PAUSE_ACTIVITY          = 101;
        public static final int PAUSE_ACTIVITY_FINISHING= 102;
@@ -1811,6 +1818,7 @@ public final class ActivityThread {
                } break;
                case PAUSE_ACTIVITY:
                    handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
                    maybeSnapshot();
                    break;
                case PAUSE_ACTIVITY_FINISHING:
                    handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2);
@@ -1853,6 +1861,7 @@ public final class ActivityThread {
                    break;
                case RECEIVER:
                    handleReceiver((ReceiverData)msg.obj);
                    maybeSnapshot();
                    break;
                case CREATE_SERVICE:
                    handleCreateService((CreateServiceData)msg.obj);
@@ -1868,6 +1877,7 @@ public final class ActivityThread {
                    break;
                case STOP_SERVICE:
                    handleStopService((IBinder)msg.obj);
                    maybeSnapshot();
                    break;
                case REQUEST_THUMBNAIL:
                    handleRequestThumbnail((IBinder)msg.obj);
@@ -1907,6 +1917,13 @@ public final class ActivityThread {
                    break;
            }
        }

        void maybeSnapshot() {
            if (mBoundApplication != null) {
                SamplingProfilerIntegration.writeSnapshot(
                        mBoundApplication.processName);
            }
        }
    }

    private final class Idler implements MessageQueue.IdleHandler {
@@ -4213,6 +4230,8 @@ public final class ActivityThread {
    }

    public static final void main(String[] args) {
        SamplingProfilerIntegration.start();

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();
@@ -4228,8 +4247,11 @@ public final class ActivityThread {

        thread.detach();
        String name;
        if (thread.mInitialApplication != null) name = thread.mInitialApplication.getPackageName();
        else name = "<unknown>";
        if (thread.mInitialApplication != null) {
            name = thread.mInitialApplication.getPackageName();
        } else {
            name = "<unknown>";
        }
        Log.i(TAG, "Main thread of " + name + " is now exiting");
    }
}
+144 −0
Original line number Diff line number Diff line
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();
    }
}
+20 −10
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.internal.os;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.net.LocalServerSocket;
import android.os.Debug;
@@ -31,6 +30,7 @@ import android.util.Log;

import dalvik.system.VMRuntime;
import dalvik.system.Zygote;
import dalvik.system.SamplingProfiler;

import java.io.BufferedReader;
import java.io.FileDescriptor;
@@ -573,6 +573,9 @@ public class ZygoteInit {

    public static void main(String argv[]) {
        try {
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();

            registerZygoteSocket();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
@@ -582,6 +585,13 @@ public class ZygoteInit {
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            if (SamplingProfilerIntegration.isEnabled()) {
                SamplingProfiler sp = SamplingProfiler.getInstance();
                sp.pause();
                SamplingProfilerIntegration.writeZygoteSnapshot();
                sp.shutDown();
            }

            // Do an initial gc to clean up after startup
            gc();

+18 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server;

import com.android.server.am.ActivityManagerService;
import com.android.server.status.StatusBarService;
import com.android.internal.os.SamplingProfilerIntegration;

import dalvik.system.VMRuntime;

@@ -41,6 +42,9 @@ import android.util.EventLog;
import android.util.Log;
import android.accounts.AccountManagerService;

import java.util.Timer;
import java.util.TimerTask;

class ServerThread extends Thread {
    private static final String TAG = "SystemServer";
    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_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
     * 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);

    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
        // as efficient as possible with its memory usage.
        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
+13 −13

File changed.

Contains only whitespace changes.