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.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);
|
||||
@ -126,7 +129,7 @@ public final class ActivityThread {
|
||||
private static final int LOG_ON_PAUSE_CALLED = 30021;
|
||||
private static final int LOG_ON_RESUME_CALLED = 30022;
|
||||
|
||||
|
||||
|
||||
public static final ActivityThread currentActivityThread() {
|
||||
return (ActivityThread)sThreadLocal.get();
|
||||
}
|
||||
@ -314,7 +317,7 @@ public final class ActivityThread {
|
||||
public ApplicationInfo getApplicationInfo() {
|
||||
return mApplicationInfo;
|
||||
}
|
||||
|
||||
|
||||
public boolean isSecurityViolation() {
|
||||
return mSecurityViolation;
|
||||
}
|
||||
@ -322,7 +325,7 @@ public final class ActivityThread {
|
||||
/**
|
||||
* Gets the array of shared libraries that are listed as
|
||||
* used by the given package.
|
||||
*
|
||||
*
|
||||
* @param packageName the name of the package (note: not its
|
||||
* file name)
|
||||
* @return null-ok; the array of shared libraries, each one
|
||||
@ -350,7 +353,7 @@ public final class ActivityThread {
|
||||
* result is a single string with the names of the libraries
|
||||
* separated by colons, or <code>null</code> if both lists
|
||||
* were <code>null</code> or empty.
|
||||
*
|
||||
*
|
||||
* @param list1 null-ok; the first list
|
||||
* @param list2 null-ok; the second list
|
||||
* @return null-ok; the combination
|
||||
@ -378,7 +381,7 @@ public final class ActivityThread {
|
||||
if (dupCheck && ArrayUtils.contains(list1, s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
@ -390,7 +393,7 @@ public final class ActivityThread {
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
synchronized (this) {
|
||||
if (mClassLoader != null) {
|
||||
@ -428,7 +431,7 @@ public final class ActivityThread {
|
||||
|
||||
if ((mSharedLibraries != null) ||
|
||||
(instrumentationLibs != null)) {
|
||||
zip =
|
||||
zip =
|
||||
combineLibs(mSharedLibraries, instrumentationLibs)
|
||||
+ ':' + zip;
|
||||
}
|
||||
@ -485,9 +488,9 @@ public final class ActivityThread {
|
||||
if (mApplication != null) {
|
||||
return mApplication;
|
||||
}
|
||||
|
||||
|
||||
Application app = null;
|
||||
|
||||
|
||||
String appClass = mApplicationInfo.className;
|
||||
if (forceDefaultAppClass || (appClass == null)) {
|
||||
appClass = "android.app.Application";
|
||||
@ -510,7 +513,7 @@ public final class ActivityThread {
|
||||
mActivityThread.mAllApplications.add(app);
|
||||
return mApplication = app;
|
||||
}
|
||||
|
||||
|
||||
public void removeContextRegistrations(Context context,
|
||||
String who, String what) {
|
||||
HashMap<BroadcastReceiver, ReceiverDispatcher> rmap =
|
||||
@ -643,7 +646,7 @@ public final class ActivityThread {
|
||||
final static class InnerReceiver extends IIntentReceiver.Stub {
|
||||
final WeakReference<ReceiverDispatcher> mDispatcher;
|
||||
final ReceiverDispatcher mStrongRef;
|
||||
|
||||
|
||||
InnerReceiver(ReceiverDispatcher rd, boolean strong) {
|
||||
mDispatcher = new WeakReference<ReceiverDispatcher>(rd);
|
||||
mStrongRef = strong ? rd : null;
|
||||
@ -661,7 +664,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final IIntentReceiver.Stub mIIntentReceiver;
|
||||
final BroadcastReceiver mReceiver;
|
||||
final Context mContext;
|
||||
@ -770,7 +773,7 @@ public final class ActivityThread {
|
||||
BroadcastReceiver getIntentReceiver() {
|
||||
return mReceiver;
|
||||
}
|
||||
|
||||
|
||||
IIntentReceiver getIIntentReceiver() {
|
||||
return mIIntentReceiver;
|
||||
}
|
||||
@ -901,7 +904,7 @@ public final class ActivityThread {
|
||||
|
||||
private static class InnerConnection extends IServiceConnection.Stub {
|
||||
final WeakReference<ServiceDispatcher> mDispatcher;
|
||||
|
||||
|
||||
InnerConnection(ServiceDispatcher sd) {
|
||||
mDispatcher = new WeakReference<ServiceDispatcher>(sd);
|
||||
}
|
||||
@ -913,7 +916,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final HashMap<ComponentName, ConnectionInfo> mActiveConnections
|
||||
= new HashMap<ComponentName, ConnectionInfo>();
|
||||
|
||||
@ -965,7 +968,7 @@ public final class ActivityThread {
|
||||
IServiceConnection getIServiceConnection() {
|
||||
return mIServiceConnection;
|
||||
}
|
||||
|
||||
|
||||
int getFlags() {
|
||||
return mFlags;
|
||||
}
|
||||
@ -1191,7 +1194,7 @@ public final class ActivityThread {
|
||||
+ " mode=" + backupMode + "}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final class CreateServiceData {
|
||||
IBinder token;
|
||||
ServiceInfo info;
|
||||
@ -1271,10 +1274,10 @@ public final class ActivityThread {
|
||||
private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
|
||||
private static final String ONE_COUNT_COLUMN = "%17s %8d";
|
||||
private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
|
||||
|
||||
|
||||
// Formatting for checkin service - update version if row format changes
|
||||
private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1;
|
||||
|
||||
|
||||
public final void schedulePauseActivity(IBinder token, boolean finished,
|
||||
boolean userLeaving, int configChanges) {
|
||||
queueOrSendMessage(
|
||||
@ -1343,7 +1346,7 @@ public final class ActivityThread {
|
||||
synchronized (mRelaunchingActivities) {
|
||||
mRelaunchingActivities.add(r);
|
||||
}
|
||||
|
||||
|
||||
queueOrSendMessage(H.RELAUNCH_ACTIVITY, r, configChanges);
|
||||
}
|
||||
|
||||
@ -1514,7 +1517,7 @@ public final class ActivityThread {
|
||||
throws RemoteException {
|
||||
receiver.performReceive(intent, resultCode, dataStr, extras, ordered);
|
||||
}
|
||||
|
||||
|
||||
public void scheduleLowMemory() {
|
||||
queueOrSendMessage(H.LOW_MEMORY, null);
|
||||
}
|
||||
@ -1530,7 +1533,7 @@ public final class ActivityThread {
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void profilerControl(boolean start, String path, ParcelFileDescriptor fd) {
|
||||
ProfilerControlData pcd = new ProfilerControlData();
|
||||
pcd.path = path;
|
||||
@ -1549,11 +1552,11 @@ public final class ActivityThread {
|
||||
Log.w(TAG, "Failed setting process group to " + group, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void getMemoryInfo(Debug.MemoryInfo outInfo) {
|
||||
Debug.getMemoryInfo(outInfo);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
long nativeMax = Debug.getNativeHeapSize() / 1024;
|
||||
@ -1589,7 +1592,7 @@ public final class ActivityThread {
|
||||
long sqliteAllocated = SQLiteDebug.getHeapAllocatedSize() / 1024;
|
||||
SQLiteDebug.PagerStats stats = new SQLiteDebug.PagerStats();
|
||||
SQLiteDebug.getPagerStats(stats);
|
||||
|
||||
|
||||
// Check to see if we were called by checkin server. If so, print terse format.
|
||||
boolean doCheckinFormat = false;
|
||||
if (args != null) {
|
||||
@ -1597,79 +1600,79 @@ public final class ActivityThread {
|
||||
if ("-c".equals(arg)) doCheckinFormat = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// For checkin, we print one long comma-separated list of values
|
||||
if (doCheckinFormat) {
|
||||
// NOTE: if you change anything significant below, also consider changing
|
||||
// ACTIVITY_THREAD_CHECKIN_VERSION.
|
||||
String processName = (mBoundApplication != null)
|
||||
String processName = (mBoundApplication != null)
|
||||
? mBoundApplication.processName : "unknown";
|
||||
|
||||
|
||||
// Header
|
||||
pw.print(ACTIVITY_THREAD_CHECKIN_VERSION); pw.print(',');
|
||||
pw.print(Process.myPid()); pw.print(',');
|
||||
pw.print(processName); pw.print(',');
|
||||
|
||||
|
||||
// Heap info - max
|
||||
pw.print(nativeMax); pw.print(',');
|
||||
pw.print(dalvikMax); pw.print(',');
|
||||
pw.print("N/A,");
|
||||
pw.print(nativeMax + dalvikMax); pw.print(',');
|
||||
|
||||
|
||||
// Heap info - allocated
|
||||
pw.print(nativeAllocated); pw.print(',');
|
||||
pw.print(dalvikAllocated); pw.print(',');
|
||||
pw.print("N/A,");
|
||||
pw.print(nativeAllocated + dalvikAllocated); pw.print(',');
|
||||
|
||||
|
||||
// Heap info - free
|
||||
pw.print(nativeFree); pw.print(',');
|
||||
pw.print(dalvikFree); pw.print(',');
|
||||
pw.print("N/A,");
|
||||
pw.print(nativeFree + dalvikFree); pw.print(',');
|
||||
|
||||
|
||||
// Heap info - proportional set size
|
||||
pw.print(memInfo.nativePss); pw.print(',');
|
||||
pw.print(memInfo.dalvikPss); pw.print(',');
|
||||
pw.print(memInfo.otherPss); pw.print(',');
|
||||
pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
|
||||
|
||||
|
||||
// Heap info - shared
|
||||
pw.print(nativeShared); pw.print(',');
|
||||
pw.print(dalvikShared); pw.print(',');
|
||||
pw.print(otherShared); pw.print(',');
|
||||
pw.print(nativeShared); pw.print(',');
|
||||
pw.print(dalvikShared); pw.print(',');
|
||||
pw.print(otherShared); pw.print(',');
|
||||
pw.print(nativeShared + dalvikShared + otherShared); pw.print(',');
|
||||
|
||||
|
||||
// Heap info - private
|
||||
pw.print(nativePrivate); pw.print(',');
|
||||
pw.print(nativePrivate); pw.print(',');
|
||||
pw.print(dalvikPrivate); pw.print(',');
|
||||
pw.print(otherPrivate); pw.print(',');
|
||||
pw.print(nativePrivate + dalvikPrivate + otherPrivate); pw.print(',');
|
||||
|
||||
|
||||
// Object counts
|
||||
pw.print(viewInstanceCount); pw.print(',');
|
||||
pw.print(viewRootInstanceCount); pw.print(',');
|
||||
pw.print(appContextInstanceCount); pw.print(',');
|
||||
pw.print(activityInstanceCount); pw.print(',');
|
||||
|
||||
|
||||
pw.print(globalAssetCount); pw.print(',');
|
||||
pw.print(globalAssetManagerCount); pw.print(',');
|
||||
pw.print(binderLocalObjectCount); pw.print(',');
|
||||
pw.print(binderProxyObjectCount); pw.print(',');
|
||||
|
||||
|
||||
pw.print(binderDeathObjectCount); pw.print(',');
|
||||
pw.print(openSslSocketCount); pw.print(',');
|
||||
|
||||
|
||||
// SQL
|
||||
pw.print(sqliteAllocated); pw.print(',');
|
||||
pw.print(stats.databaseBytes / 1024); pw.print(',');
|
||||
pw.print(stats.databaseBytes / 1024); pw.print(',');
|
||||
pw.print(stats.numPagers); pw.print(',');
|
||||
pw.print((stats.totalBytes - stats.referencedBytes) / 1024); pw.print(',');
|
||||
pw.print(stats.referencedBytes / 1024); pw.print('\n');
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// otherwise, show human-readable format
|
||||
printRow(pw, HEAP_COLUMN, "", "native", "dalvik", "other", "total");
|
||||
printRow(pw, HEAP_COLUMN, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax);
|
||||
@ -1702,7 +1705,7 @@ public final class ActivityThread {
|
||||
printRow(pw, ONE_COUNT_COLUMN, "Death Recipients:", binderDeathObjectCount);
|
||||
|
||||
printRow(pw, ONE_COUNT_COLUMN, "OpenSSL Sockets:", openSslSocketCount);
|
||||
|
||||
|
||||
// SQLite mem info
|
||||
pw.println(" ");
|
||||
pw.println(" SQL");
|
||||
@ -1711,7 +1714,7 @@ public final class ActivityThread {
|
||||
printRow(pw, TWO_COUNT_COLUMNS, "numPagers:", stats.numPagers, "inactivePageKB:",
|
||||
(stats.totalBytes - stats.referencedBytes) / 1024);
|
||||
printRow(pw, ONE_COUNT_COLUMN, "activePageKB:", stats.referencedBytes / 1024);
|
||||
|
||||
|
||||
// Asset details.
|
||||
String assetAlloc = AssetManager.getAssetAllocations();
|
||||
if (assetAlloc != null) {
|
||||
@ -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 {
|
||||
@ -1947,13 +1964,13 @@ public final class ActivityThread {
|
||||
final private String mResDir;
|
||||
final private float mScale;
|
||||
final private int mHash;
|
||||
|
||||
|
||||
ResourcesKey(String resDir, float scale) {
|
||||
mResDir = resDir;
|
||||
mScale = scale;
|
||||
mHash = mResDir.hashCode() << 2 + (int) (mScale * 2);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return mHash;
|
||||
@ -2004,7 +2021,7 @@ public final class ActivityThread {
|
||||
final ArrayList<ActivityRecord> mRelaunchingActivities
|
||||
= new ArrayList<ActivityRecord>();
|
||||
Configuration mPendingConfiguration = null;
|
||||
|
||||
|
||||
// These can be accessed by multiple threads; mPackages is the lock.
|
||||
// XXX For now we keep around information about all packages we have
|
||||
// seen, not removing entries from this map.
|
||||
@ -2139,7 +2156,7 @@ public final class ActivityThread {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ActivityThread() {
|
||||
}
|
||||
|
||||
@ -2172,11 +2189,11 @@ public final class ActivityThread {
|
||||
public Application getApplication() {
|
||||
return mInitialApplication;
|
||||
}
|
||||
|
||||
|
||||
public String getProcessName() {
|
||||
return mBoundApplication.processName;
|
||||
}
|
||||
|
||||
|
||||
public ApplicationContext getSystemContext() {
|
||||
synchronized (this) {
|
||||
if (mSystemContext == null) {
|
||||
@ -2231,7 +2248,7 @@ public final class ActivityThread {
|
||||
}
|
||||
return aInfo;
|
||||
}
|
||||
|
||||
|
||||
public final Activity startActivityNow(Activity parent, String id,
|
||||
Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
|
||||
Object lastNonConfigurationInstance) {
|
||||
@ -2314,7 +2331,7 @@ public final class ActivityThread {
|
||||
r.packageInfo = getPackageInfo(aInfo.applicationInfo,
|
||||
Context.CONTEXT_INCLUDE_CODE);
|
||||
}
|
||||
|
||||
|
||||
ComponentName component = r.intent.getComponent();
|
||||
if (component == null) {
|
||||
component = r.intent.resolveActivity(
|
||||
@ -2346,7 +2363,7 @@ public final class ActivityThread {
|
||||
|
||||
try {
|
||||
Application app = r.packageInfo.makeApplication(false);
|
||||
|
||||
|
||||
if (localLOGV) Log.v(TAG, "Performing launch of " + r);
|
||||
if (localLOGV) Log.v(
|
||||
TAG, r + ": app=" + app
|
||||
@ -2365,7 +2382,7 @@ public final class ActivityThread {
|
||||
r.ident, app, r.intent, r.activityInfo, title, r.parent,
|
||||
r.embeddedID, r.lastNonConfigurationInstance,
|
||||
r.lastNonConfigurationChildInstances, config);
|
||||
|
||||
|
||||
if (customIntent != null) {
|
||||
activity.mIntent = customIntent;
|
||||
}
|
||||
@ -2503,7 +2520,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final void handleNewIntent(NewIntentData data) {
|
||||
performNewIntents(data.token, data.intents);
|
||||
}
|
||||
@ -2541,7 +2558,7 @@ public final class ActivityThread {
|
||||
|
||||
try {
|
||||
Application app = packageInfo.makeApplication(false);
|
||||
|
||||
|
||||
if (localLOGV) Log.v(
|
||||
TAG, "Performing receive of " + data.intent
|
||||
+ ": app=" + app
|
||||
@ -2598,7 +2615,7 @@ public final class ActivityThread {
|
||||
+ " already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
BackupAgent agent = null;
|
||||
String classname = data.appInfo.backupAgentName;
|
||||
if (classname == null) {
|
||||
@ -2652,7 +2669,7 @@ public final class ActivityThread {
|
||||
// Tear down a BackupAgent
|
||||
private final void handleDestroyBackupAgent(CreateBackupAgentData data) {
|
||||
if (DEBUG_BACKUP) Log.v(TAG, "handleDestroyBackupAgent: " + data);
|
||||
|
||||
|
||||
PackageInfo packageInfo = getPackageInfoNoCheck(data.appInfo);
|
||||
String packageName = packageInfo.mPackageName;
|
||||
BackupAgent agent = mBackupAgents.get(packageName);
|
||||
@ -2857,9 +2874,9 @@ public final class ActivityThread {
|
||||
}
|
||||
r.activity.performResume();
|
||||
|
||||
EventLog.writeEvent(LOG_ON_RESUME_CALLED,
|
||||
EventLog.writeEvent(LOG_ON_RESUME_CALLED,
|
||||
r.activity.getComponentName().getClassName());
|
||||
|
||||
|
||||
r.paused = false;
|
||||
r.stopped = false;
|
||||
if (r.activity.mStartedActivity) {
|
||||
@ -2895,7 +2912,7 @@ public final class ActivityThread {
|
||||
|
||||
final int forwardBit = isForward ?
|
||||
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
|
||||
|
||||
|
||||
// If the window hasn't yet been added to the window manager,
|
||||
// and this guy didn't finish itself or start another activity,
|
||||
// then go ahead and add the window.
|
||||
@ -3014,7 +3031,7 @@ public final class ActivityThread {
|
||||
if (userLeaving) {
|
||||
performUserLeavingActivity(r);
|
||||
}
|
||||
|
||||
|
||||
r.activity.mConfigChangeFlags |= configChanges;
|
||||
Bundle state = performPauseActivity(token, finished, true);
|
||||
|
||||
@ -3191,7 +3208,7 @@ public final class ActivityThread {
|
||||
+ " win=" + r.window);
|
||||
|
||||
updateVisibility(r, show);
|
||||
|
||||
|
||||
// Tell activity manager we have been stopped.
|
||||
try {
|
||||
ActivityManagerNative.getDefault().activityStopped(
|
||||
@ -3307,7 +3324,7 @@ public final class ActivityThread {
|
||||
try {
|
||||
r.activity.mCalled = false;
|
||||
mInstrumentation.callActivityOnPause(r.activity);
|
||||
EventLog.writeEvent(LOG_ON_PAUSE_CALLED,
|
||||
EventLog.writeEvent(LOG_ON_PAUSE_CALLED,
|
||||
r.activity.getComponentName().getClassName());
|
||||
if (!r.activity.mCalled) {
|
||||
throw new SuperNotCalledException(
|
||||
@ -3364,7 +3381,7 @@ public final class ActivityThread {
|
||||
+ ": " + e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
try {
|
||||
r.activity.mCalled = false;
|
||||
@ -3446,7 +3463,7 @@ public final class ActivityThread {
|
||||
unscheduleGcIdler();
|
||||
|
||||
Configuration changedConfig = null;
|
||||
|
||||
|
||||
// First: make sure we have the most recent configuration and most
|
||||
// recent version of the activity, or skip it if some previous call
|
||||
// had taken a more recent version.
|
||||
@ -3463,38 +3480,38 @@ public final class ActivityThread {
|
||||
N--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (tmp == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (mPendingConfiguration != null) {
|
||||
changedConfig = mPendingConfiguration;
|
||||
mPendingConfiguration = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If there was a pending configuration change, execute it first.
|
||||
if (changedConfig != null) {
|
||||
handleConfigurationChanged(changedConfig);
|
||||
}
|
||||
|
||||
|
||||
ActivityRecord r = mActivities.get(tmp.token);
|
||||
if (localLOGV) Log.v(TAG, "Handling relaunch of " + r);
|
||||
if (r == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
r.activity.mConfigChangeFlags |= configChanges;
|
||||
Intent currentIntent = r.activity.mIntent;
|
||||
|
||||
|
||||
Bundle savedState = null;
|
||||
if (!r.paused) {
|
||||
savedState = performPauseActivity(r.token, false, true);
|
||||
}
|
||||
|
||||
|
||||
handleDestroyActivity(r.token, false, configChanges, true);
|
||||
|
||||
|
||||
r.activity = null;
|
||||
r.window = null;
|
||||
r.hideForNow = false;
|
||||
@ -3518,7 +3535,7 @@ public final class ActivityThread {
|
||||
if (savedState != null) {
|
||||
r.state = savedState;
|
||||
}
|
||||
|
||||
|
||||
handleLaunchActivity(r, currentIntent);
|
||||
}
|
||||
|
||||
@ -3548,7 +3565,7 @@ public final class ActivityThread {
|
||||
boolean allActivities, Configuration newConfig) {
|
||||
ArrayList<ComponentCallbacks> callbacks
|
||||
= new ArrayList<ComponentCallbacks>();
|
||||
|
||||
|
||||
if (mActivities.size() > 0) {
|
||||
Iterator<ActivityRecord> it = mActivities.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
@ -3589,10 +3606,10 @@ public final class ActivityThread {
|
||||
for (int i=0; i<N; i++) {
|
||||
callbacks.add(mAllApplications.get(i));
|
||||
}
|
||||
|
||||
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
|
||||
private final void performConfigurationChanged(
|
||||
ComponentCallbacks cb, Configuration config) {
|
||||
// Only for Activity objects, check that they actually call up to their
|
||||
@ -3602,18 +3619,18 @@ public final class ActivityThread {
|
||||
if (activity != null) {
|
||||
activity.mCalled = false;
|
||||
}
|
||||
|
||||
|
||||
boolean shouldChangeConfig = false;
|
||||
if ((activity == null) || (activity.mCurrentConfig == null)) {
|
||||
shouldChangeConfig = true;
|
||||
} else {
|
||||
|
||||
|
||||
// If the new config is the same as the config this Activity
|
||||
// is already running with then don't bother calling
|
||||
// onConfigurationChanged
|
||||
int diff = activity.mCurrentConfig.diff(config);
|
||||
if (diff != 0) {
|
||||
|
||||
|
||||
// If this activity doesn't handle any of the config changes
|
||||
// then don't bother calling onConfigurationChanged as we're
|
||||
// going to destroy it.
|
||||
@ -3622,10 +3639,10 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (shouldChangeConfig) {
|
||||
cb.onConfigurationChanged(config);
|
||||
|
||||
|
||||
if (activity != null) {
|
||||
if (!activity.mCalled) {
|
||||
throw new SuperNotCalledException(
|
||||
@ -3639,17 +3656,17 @@ public final class ActivityThread {
|
||||
}
|
||||
|
||||
final void handleConfigurationChanged(Configuration config) {
|
||||
|
||||
|
||||
synchronized (mRelaunchingActivities) {
|
||||
if (mPendingConfiguration != null) {
|
||||
config = mPendingConfiguration;
|
||||
mPendingConfiguration = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ArrayList<ComponentCallbacks> callbacks
|
||||
= new ArrayList<ComponentCallbacks>();
|
||||
|
||||
|
||||
synchronized(mPackages) {
|
||||
if (mConfiguration == null) {
|
||||
mConfiguration = new Configuration();
|
||||
@ -3684,10 +3701,10 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
callbacks = collectComponentCallbacksLocked(false, config);
|
||||
}
|
||||
|
||||
|
||||
final int N = callbacks.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
performConfigurationChanged(callbacks.get(i), config);
|
||||
@ -3699,7 +3716,7 @@ public final class ActivityThread {
|
||||
if (r == null || r.activity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
performConfigurationChanged(r.activity, mConfiguration);
|
||||
}
|
||||
|
||||
@ -3722,7 +3739,7 @@ public final class ActivityThread {
|
||||
Debug.stopMethodTracing();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final void handleLowMemory() {
|
||||
ArrayList<ComponentCallbacks> callbacks
|
||||
= new ArrayList<ComponentCallbacks>();
|
||||
@ -3730,7 +3747,7 @@ public final class ActivityThread {
|
||||
synchronized(mPackages) {
|
||||
callbacks = collectComponentCallbacksLocked(true, null);
|
||||
}
|
||||
|
||||
|
||||
final int N = callbacks.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
callbacks.get(i).onLowMemory();
|
||||
@ -3741,7 +3758,7 @@ public final class ActivityThread {
|
||||
int sqliteReleased = SQLiteDatabase.releaseMemory();
|
||||
EventLog.writeEvent(SQLITE_MEM_RELEASED_EVENT_LOG_TAG, sqliteReleased);
|
||||
}
|
||||
|
||||
|
||||
// Ask graphics to free up as much as possible (font/image caches)
|
||||
Canvas.freeCaches();
|
||||
|
||||
@ -3788,7 +3805,7 @@ public final class ActivityThread {
|
||||
== 0) {
|
||||
Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
if (data.debugMode != IApplicationThread.DEBUG_OFF) {
|
||||
// XXX should have option to change the port.
|
||||
Debug.changeDebugPort(8100);
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public class RuntimeInit {
|
||||
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
|
||||
|
||||
int hasQwerty = getQwertyKeyboard();
|
||||
|
||||
|
||||
if (Config.LOGV) Log.d(TAG, ">>>>> qwerty keyboard = " + hasQwerty);
|
||||
if (hasQwerty == 1) {
|
||||
System.setProperty("qwerty", "1");
|
||||
@ -133,13 +133,13 @@ public class RuntimeInit {
|
||||
* @param className Fully-qualified class name
|
||||
* @param argv Argument vector for main()
|
||||
*/
|
||||
private static void invokeStaticMain(String className, String[] argv)
|
||||
private static void invokeStaticMain(String className, String[] argv)
|
||||
throws ZygoteInit.MethodAndArgsCaller {
|
||||
|
||||
|
||||
// We want to be fairly aggressive about heap utilization, to avoid
|
||||
// holding on to a lot of memory that isn't needed.
|
||||
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
|
||||
|
||||
|
||||
Class<?> cl;
|
||||
|
||||
try {
|
||||
@ -178,7 +178,7 @@ public class RuntimeInit {
|
||||
|
||||
public static final void main(String[] argv) {
|
||||
commonInit();
|
||||
|
||||
|
||||
/*
|
||||
* Now that we're running in interpreted code, call back into native code
|
||||
* to run the system.
|
||||
@ -187,7 +187,7 @@ public class RuntimeInit {
|
||||
|
||||
if (Config.LOGV) Log.d(TAG, "Leaving RuntimeInit!");
|
||||
}
|
||||
|
||||
|
||||
public static final native void finishInit();
|
||||
|
||||
/**
|
||||
@ -236,7 +236,7 @@ public class RuntimeInit {
|
||||
}
|
||||
|
||||
// Remaining arguments are passed to the start class's static main
|
||||
|
||||
|
||||
String startClass = argv[curArg++];
|
||||
String[] startArgs = new String[argv.length - curArg];
|
||||
|
||||
@ -245,28 +245,28 @@ public class RuntimeInit {
|
||||
}
|
||||
|
||||
public static final native void zygoteInitNative();
|
||||
|
||||
|
||||
/**
|
||||
* Returns 1 if the computer is on. If the computer isn't on, the value returned by this method is undefined.
|
||||
*/
|
||||
public static final native int isComputerOn();
|
||||
|
||||
/**
|
||||
* Turns the computer on if the computer is off. If the computer is on, the behavior of this method is undefined.
|
||||
* Turns the computer on if the computer is off. If the computer is on, the behavior of this method is undefined.
|
||||
*/
|
||||
public static final native void turnComputerOn();
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return 1 if the device has a qwerty keyboard
|
||||
*/
|
||||
public static native int getQwertyKeyboard();
|
||||
|
||||
|
||||
/**
|
||||
* Report a fatal error in the current process. If this is a user-process,
|
||||
* a dialog may be displayed informing the user of the error. This
|
||||
* function does not return; it forces the current process to exit.
|
||||
*
|
||||
*
|
||||
* @param tag to use when logging the error
|
||||
* @param t exception that was generated by the error
|
||||
*/
|
||||
@ -405,7 +405,7 @@ public class RuntimeInit {
|
||||
/**
|
||||
* Replay an encoded CrashData record back into a useable CrashData record. This can be
|
||||
* helpful for providing debugging output after a process error.
|
||||
*
|
||||
*
|
||||
* @param crashDataBytes The byte array containing the encoded crash record
|
||||
* @return new CrashData record, or null if could not create one.
|
||||
*/
|
||||
|
@ -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.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;
|
||||
@ -73,7 +73,7 @@ public class ZygoteInit {
|
||||
* never gets destroyed.
|
||||
*/
|
||||
private static Resources mResources;
|
||||
|
||||
|
||||
/**
|
||||
* The number of times that the main Zygote loop
|
||||
* should run before calling gc() again.
|
||||
@ -192,7 +192,7 @@ public class ZygoteInit {
|
||||
* RuntimeException on failure.
|
||||
*/
|
||||
private static ZygoteConnection acceptCommandPeer() {
|
||||
try {
|
||||
try {
|
||||
return new ZygoteConnection(sServerSocket.accept());
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(
|
||||
@ -251,7 +251,7 @@ public class ZygoteInit {
|
||||
*/
|
||||
private static void preloadClasses() {
|
||||
final VMRuntime runtime = VMRuntime.getRuntime();
|
||||
|
||||
|
||||
InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(
|
||||
PRELOADED_CLASSES);
|
||||
if (is == null) {
|
||||
@ -259,7 +259,7 @@ public class ZygoteInit {
|
||||
} else {
|
||||
Log.i(TAG, "Preloading classes...");
|
||||
long startTime = SystemClock.uptimeMillis();
|
||||
|
||||
|
||||
// Drop root perms while running static initializers.
|
||||
setEffectiveGroup(UNPRIVILEGED_GID);
|
||||
setEffectiveUser(UNPRIVILEGED_UID);
|
||||
@ -275,7 +275,7 @@ public class ZygoteInit {
|
||||
Debug.startAllocCounting();
|
||||
|
||||
try {
|
||||
BufferedReader br
|
||||
BufferedReader br
|
||||
= new BufferedReader(new InputStreamReader(is), 256);
|
||||
|
||||
int count = 0;
|
||||
@ -394,7 +394,7 @@ public class ZygoteInit {
|
||||
*/
|
||||
private static void preloadResources() {
|
||||
final VMRuntime runtime = VMRuntime.getRuntime();
|
||||
|
||||
|
||||
Debug.startAllocCounting();
|
||||
try {
|
||||
runtime.gcSoftReferences();
|
||||
@ -527,7 +527,7 @@ public class ZygoteInit {
|
||||
/**
|
||||
* Prepare the arguments and fork for the system server process.
|
||||
*/
|
||||
private static boolean startSystemServer()
|
||||
private static boolean startSystemServer()
|
||||
throws MethodAndArgsCaller, RuntimeException {
|
||||
/* Hardcoded command line to start the system server */
|
||||
String args[] = {
|
||||
@ -561,8 +561,8 @@ public class ZygoteInit {
|
||||
parsedArgs.gids, debugFlags, null);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* For child process */
|
||||
if (pid == 0) {
|
||||
handleSystemServerProcess(parsedArgs);
|
||||
@ -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();
|
||||
|
||||
|
Reference in New Issue
Block a user