diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-08-15 17:40:28 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2011-08-15 17:55:57 -0700 |
commit | 62f20ecf492d2b29881bba307c79ff55e68760e6 (patch) | |
tree | 58ea602138a28fb3555368900acbad6219ae2de2 | |
parent | 0f2da17a9523fc40bceb5209cabd044df648e98e (diff) | |
download | frameworks_base-62f20ecf492d2b29881bba307c79ff55e68760e6.zip frameworks_base-62f20ecf492d2b29881bba307c79ff55e68760e6.tar.gz frameworks_base-62f20ecf492d2b29881bba307c79ff55e68760e6.tar.bz2 |
Add new am option to profile the launching of an activity.
Change-Id: Ie71a8043eafe41f53a0b3dbb5170276d87acbc9b
-rw-r--r-- | cmds/am/src/com/android/commands/am/Am.java | 41 | ||||
-rw-r--r-- | core/java/android/app/Activity.java | 3 | ||||
-rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 41 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 106 | ||||
-rw-r--r-- | core/java/android/app/ApplicationThreadNative.java | 34 | ||||
-rw-r--r-- | core/java/android/app/IActivityManager.java | 9 | ||||
-rw-r--r-- | core/java/android/app/IApplicationThread.java | 6 | ||||
-rw-r--r-- | core/java/android/app/Instrumentation.java | 4 | ||||
-rw-r--r-- | core/java/android/os/ParcelFileDescriptor.java | 10 | ||||
-rwxr-xr-x | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 6 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 190 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityStack.java | 49 |
12 files changed, 419 insertions, 80 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 6dfa12b..2937d27 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -57,6 +57,9 @@ public class Am { private boolean mDebugOption = false; private boolean mWaitOption = false; + private String mProfileFile; + private boolean mProfileAutoStop; + // These are magic strings understood by the Eclipse plugin. private static final String FATAL_ERROR_CODE = "Error type 1"; private static final String NO_SYSTEM_ERROR_CODE = "Error type 2"; @@ -249,6 +252,12 @@ public class Am { mDebugOption = true; } else if (opt.equals("-W")) { mWaitOption = true; + } else if (opt.equals("-P")) { + mProfileFile = nextArgRequired(); + mProfileAutoStop = true; + } else if (opt.equals("--start-profiler")) { + mProfileFile = nextArgRequired(); + mProfileAutoStop = false; } else { System.err.println("Error: Unknown option: " + opt); showUsage(); @@ -294,16 +303,34 @@ public class Am { Intent intent = makeIntent(); System.out.println("Starting: " + intent); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + ParcelFileDescriptor fd = null; + + if (mProfileFile != null) { + try { + fd = ParcelFileDescriptor.open( + new File(mProfileFile), + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_READ_WRITE); + } catch (FileNotFoundException e) { + System.err.println("Error: Unable to open file: " + mProfileFile); + return; + } + } + // XXX should do something to determine the MIME type. IActivityManager.WaitResult result = null; int res; if (mWaitOption) { result = mAm.startActivityAndWait(null, intent, intent.getType(), - null, 0, null, null, 0, false, mDebugOption); + null, 0, null, null, 0, false, mDebugOption, + mProfileFile, fd, mProfileAutoStop); res = result.result; } else { res = mAm.startActivity(null, intent, intent.getType(), - null, 0, null, null, 0, false, mDebugOption); + null, 0, null, null, 0, false, mDebugOption, + mProfileFile, fd, mProfileAutoStop); } PrintStream out = mWaitOption ? System.out : System.err; boolean launched = false; @@ -483,7 +510,7 @@ public class Am { wall = "--wall".equals(nextOption()); process = nextArgRequired(); } else if ("stop".equals(cmd)) { - process = nextArgRequired(); + process = nextArg(); } else { // Compatibility with old syntax: process is specified first. process = cmd; @@ -1076,14 +1103,14 @@ public class Am { private static void showUsage() { System.err.println( "usage: am [subcommand] [options]\n" + - "usage: am start [-D] [-W] <INTENT>\n" + + "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>] <INTENT>\n" + " am startservice <INTENT>\n" + " am force-stop <PACKAGE>\n" + " am broadcast <INTENT>\n" + - " am instrument [-r] [-e <NAME> <VALUE>] [-p] [-w]\n" + + " am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" + " [--no-window-animation] <COMPONENT>\n" + " am profile [looper] start <PROCESS> <FILE>\n" + - " am profile [looper] stop <PROCESS>\n" + + " am profile [looper] stop [<PROCESS>]\n" + " am dumpheap [flags] <PROCESS> <FILE>\n" + " am monitor [--gdb <port>]\n" + " am screen-compat [on|off] <PACKAGE>\n" + @@ -1092,6 +1119,8 @@ public class Am { "am start: start an Activity. Options are:\n" + " -D: enable debugging\n" + " -W: wait for launch to complete\n" + + " --start-profiler <FILE>: start profiler and send results to <FILE>\n" + + " -P <FILE>: like above, but profiling stops when app goes idle\n" + "\n" + "am startservice: start a Service.\n" + "\n" + diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 929867b..1271ddd 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -3353,7 +3353,8 @@ public class Activity extends ContextThemeWrapper intent, intent.resolveTypeIfNeeded( getContentResolver()), null, 0, - mToken, mEmbeddedID, requestCode, true, false); + mToken, mEmbeddedID, requestCode, true, false, + null, null, false); } catch (RemoteException e) { // Empty } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index a73e10a..8901fc8 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -124,9 +124,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM int requestCode = data.readInt(); boolean onlyIfNeeded = data.readInt() != 0; boolean debug = data.readInt() != 0; + String profileFile = data.readString(); + ParcelFileDescriptor profileFd = data.readInt() != 0 + ? data.readFileDescriptor() : null; + boolean autoStopProfiler = data.readInt() != 0; int result = startActivity(app, intent, resolvedType, grantedUriPermissions, grantedMode, resultTo, resultWho, - requestCode, onlyIfNeeded, debug); + requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler); reply.writeNoException(); reply.writeInt(result); return true; @@ -146,9 +150,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM int requestCode = data.readInt(); boolean onlyIfNeeded = data.readInt() != 0; boolean debug = data.readInt() != 0; + String profileFile = data.readString(); + ParcelFileDescriptor profileFd = data.readInt() != 0 + ? data.readFileDescriptor() : null; + boolean autoStopProfiler = data.readInt() != 0; WaitResult result = startActivityAndWait(app, intent, resolvedType, grantedUriPermissions, grantedMode, resultTo, resultWho, - requestCode, onlyIfNeeded, debug); + requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler); reply.writeNoException(); result.writeToParcel(reply, 0); return true; @@ -349,8 +357,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM if (data.readInt() != 0) { config = Configuration.CREATOR.createFromParcel(data); } + boolean stopProfiling = data.readInt() != 0; if (token != null) { - activityIdle(token, config); + activityIdle(token, config, stopProfiling); } reply.writeNoException(); return true; @@ -1572,7 +1581,8 @@ class ActivityManagerProxy implements IActivityManager String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, boolean onlyIfNeeded, - boolean debug) throws RemoteException { + boolean debug, String profileFile, ParcelFileDescriptor profileFd, + boolean autoStopProfiler) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -1586,6 +1596,14 @@ class ActivityManagerProxy implements IActivityManager data.writeInt(requestCode); data.writeInt(onlyIfNeeded ? 1 : 0); data.writeInt(debug ? 1 : 0); + data.writeString(profileFile); + if (profileFd != null) { + data.writeInt(1); + profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + } else { + data.writeInt(0); + } + data.writeInt(autoStopProfiler ? 1 : 0); mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0); reply.readException(); int result = reply.readInt(); @@ -1597,7 +1615,8 @@ class ActivityManagerProxy implements IActivityManager String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, boolean onlyIfNeeded, - boolean debug) throws RemoteException { + boolean debug, String profileFile, ParcelFileDescriptor profileFd, + boolean autoStopProfiler) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -1611,6 +1630,14 @@ class ActivityManagerProxy implements IActivityManager data.writeInt(requestCode); data.writeInt(onlyIfNeeded ? 1 : 0); data.writeInt(debug ? 1 : 0); + data.writeString(profileFile); + if (profileFd != null) { + data.writeInt(1); + profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + } else { + data.writeInt(0); + } + data.writeInt(autoStopProfiler ? 1 : 0); mRemote.transact(START_ACTIVITY_AND_WAIT_TRANSACTION, data, reply, 0); reply.readException(); WaitResult result = WaitResult.CREATOR.createFromParcel(reply); @@ -1829,7 +1856,8 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - public void activityIdle(IBinder token, Configuration config) throws RemoteException + public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) + throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -1841,6 +1869,7 @@ class ActivityManagerProxy implements IActivityManager } else { data.writeInt(0); } + data.writeInt(stopProfiling ? 1 : 0); mRemote.transact(ACTIVITY_IDLE_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY); reply.readException(); data.recycle(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d5f630a..e376220 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -225,6 +225,10 @@ public final class ActivityThread { Configuration createdConfig; ActivityClientRecord nextIdle; + String profileFile; + ParcelFileDescriptor profileFd; + boolean autoStopProfiler; + ActivityInfo activityInfo; CompatibilityInfo compatInfo; LoadedApk packageInfo; @@ -361,6 +365,9 @@ public final class ActivityThread { List<ProviderInfo> providers; ComponentName instrumentationName; String profileFile; + ParcelFileDescriptor profileFd; + boolean autoStopProfiler; + boolean profiling; Bundle instrumentationArgs; IInstrumentationWatcher instrumentationWatcher; int debugMode; @@ -371,6 +378,57 @@ public final class ActivityThread { public String toString() { return "AppBindData{appInfo=" + appInfo + "}"; } + public void setProfiler(String file, ParcelFileDescriptor fd) { + if (profiling) { + if (fd != null) { + try { + fd.close(); + } catch (IOException e) { + } + } + return; + } + if (profileFd != null) { + try { + profileFd.close(); + } catch (IOException e) { + } + } + profileFile = file; + profileFd = fd; + } + public void startProfiling() { + if (profileFd == null || profiling) { + return; + } + try { + Debug.startMethodTracing(profileFile, profileFd.getFileDescriptor(), + 8 * 1024 * 1024, 0); + profiling = true; + } catch (RuntimeException e) { + Slog.w(TAG, "Profiling failed on path " + profileFile); + try { + profileFd.close(); + profileFd = null; + } catch (IOException e2) { + Slog.w(TAG, "Failure closing profile fd", e2); + } + } + } + public void stopProfiling() { + if (profiling) { + profiling = false; + Debug.stopMethodTracing(); + if (profileFd != null) { + try { + profileFd.close(); + } catch (IOException e) { + } + } + profileFd = null; + profileFile = null; + } + } } static final class DumpComponentInfo { @@ -463,7 +521,8 @@ public final class ActivityThread { public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, CompatibilityInfo compatInfo, Bundle state, List<ResultInfo> pendingResults, - List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) { + List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, + String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { ActivityClientRecord r = new ActivityClientRecord(); r.token = token; @@ -479,6 +538,10 @@ public final class ActivityThread { r.startsNotResumed = notResumed; r.isForward = isForward; + r.profileFile = profileName; + r.profileFd = profileFd; + r.autoStopProfiler = autoStopProfiler; + queueOrSendMessage(H.LAUNCH_ACTIVITY, r); } @@ -579,6 +642,7 @@ public final class ActivityThread { public final void bindApplication(String processName, ApplicationInfo appInfo, List<ProviderInfo> providers, ComponentName instrumentationName, String profileFile, + ParcelFileDescriptor profileFd, boolean autoStopProfiler, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, int debugMode, boolean isRestrictedBackupMode, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, @@ -596,7 +660,8 @@ public final class ActivityThread { data.appInfo = appInfo; data.providers = providers; data.instrumentationName = instrumentationName; - data.profileFile = profileFile; + data.setProfiler(profileFile, profileFd); + data.autoStopProfiler = false; data.instrumentationArgs = instrumentationArgs; data.instrumentationWatcher = instrumentationWatcher; data.debugMode = debugMode; @@ -1225,6 +1290,10 @@ public final class ActivityThread { private class Idler implements MessageQueue.IdleHandler { public final boolean queueIdle() { ActivityClientRecord a = mNewActivities; + boolean stopProfiling = false; + if (mBoundApplication.profileFd != null && mBoundApplication.autoStopProfiler) { + stopProfiling = true; + } if (a != null) { mNewActivities = null; IActivityManager am = ActivityManagerNative.getDefault(); @@ -1236,7 +1305,7 @@ public final class ActivityThread { (a.activity != null && a.activity.mFinished)); if (a.activity != null && !a.activity.mFinished) { try { - am.activityIdle(a.token, a.createdConfig); + am.activityIdle(a.token, a.createdConfig, stopProfiling); a.createdConfig = null; } catch (RemoteException ex) { // Ignore @@ -1247,6 +1316,9 @@ public final class ActivityThread { prev.nextIdle = null; } while (a != null); } + if (stopProfiling) { + mBoundApplication.stopProfiling(); + } ensureJitEnabled(); return false; } @@ -1560,7 +1632,8 @@ public final class ActivityThread { } public boolean isProfiling() { - return mBoundApplication != null && mBoundApplication.profileFile != null; + return mBoundApplication != null && mBoundApplication.profileFile != null + && mBoundApplication.profileFd == null; } public String getProfileFilePath() { @@ -1870,6 +1943,13 @@ public final class ActivityThread { // we are back active so skip it. unscheduleGcIdler(); + Slog.i(TAG, "Launch: profileFd=" + r.profileFile + " stop=" + r.autoStopProfiler); + if (r.profileFd != null) { + mBoundApplication.setProfiler(r.profileFile, r.profileFd); + mBoundApplication.startProfiling(); + mBoundApplication.autoStopProfiler = r.autoStopProfiler; + } + if (localLOGV) Slog.v( TAG, "Handling launch of " + r); Activity a = performLaunchActivity(r, customIntent); @@ -3489,8 +3569,9 @@ public final class ActivityThread { ViewDebug.startLooperProfiling(pcd.path, pcd.fd.getFileDescriptor()); break; default: - Debug.startMethodTracing(pcd.path, pcd.fd.getFileDescriptor(), - 8 * 1024 * 1024, 0); + mBoundApplication.setProfiler(pcd.path, pcd.fd); + mBoundApplication.autoStopProfiler = false; + mBoundApplication.startProfiling(); break; } } catch (RuntimeException e) { @@ -3509,9 +3590,8 @@ public final class ActivityThread { ViewDebug.stopLooperProfiling(); break; default: - Debug.stopMethodTracing(); + mBoundApplication.stopProfiling(); break; - } } } @@ -3607,6 +3687,10 @@ public final class ActivityThread { Process.setArgV0(data.processName); android.ddm.DdmHandleAppName.setAppName(data.processName); + if (data.profileFd != null) { + data.startProfiling(); + } + // If the app is Honeycomb MR1 or earlier, switch its AsyncTask // implementation to use the pool executor. Normally, we use the // serialized executor as the default. This has to happen in the @@ -3745,7 +3829,8 @@ public final class ActivityThread { mInstrumentation.init(this, instrContext, appContext, new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher); - if (data.profileFile != null && !ii.handleProfiling) { + if (data.profileFile != null && !ii.handleProfiling + && data.profileFd == null) { data.handlingProfiling = true; File file = new File(data.profileFile); file.getParentFile().mkdirs(); @@ -3799,7 +3884,8 @@ public final class ActivityThread { /*package*/ final void finishInstrumentation(int resultCode, Bundle results) { IActivityManager am = ActivityManagerNative.getDefault(); - if (mBoundApplication.profileFile != null && mBoundApplication.handlingProfiling) { + if (mBoundApplication.profileFile != null && mBoundApplication.handlingProfiling + && mBoundApplication.profileFd == null) { Debug.stopMethodTracing(); } //Slog.i(TAG, "am: " + ActivityManagerNative.getDefault() diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index bea057e..0a6fdd4 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -138,8 +138,12 @@ public abstract class ApplicationThreadNative extends Binder List<Intent> pi = data.createTypedArrayList(Intent.CREATOR); boolean notResumed = data.readInt() != 0; boolean isForward = data.readInt() != 0; + String profileName = data.readString(); + ParcelFileDescriptor profileFd = data.readInt() != 0 + ? data.readFileDescriptor() : null; + boolean autoStopProfiler = data.readInt() != 0; scheduleLaunchActivity(intent, b, ident, info, compatInfo, state, ri, pi, - notResumed, isForward); + notResumed, isForward, profileName, profileFd, autoStopProfiler); return true; } @@ -255,6 +259,9 @@ public abstract class ApplicationThreadNative extends Binder ComponentName testName = (data.readInt() != 0) ? new ComponentName(data) : null; String profileName = data.readString(); + ParcelFileDescriptor profileFd = data.readInt() != 0 + ? data.readFileDescriptor() : null; + boolean autoStopProfiler = data.readInt() != 0; Bundle testArgs = data.readBundle(); IBinder binder = data.readStrongBinder(); IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder); @@ -265,7 +272,7 @@ public abstract class ApplicationThreadNative extends Binder HashMap<String, IBinder> services = data.readHashMap(null); Bundle coreSettings = data.readBundle(); bindApplication(packageName, info, - providers, testName, profileName, + providers, testName, profileName, profileFd, autoStopProfiler, testArgs, testWatcher, testMode, restrictedBackupMode, config, compatInfo, services, coreSettings); return true; @@ -624,7 +631,8 @@ class ApplicationThreadProxy implements IApplicationThread { public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, CompatibilityInfo compatInfo, Bundle state, List<ResultInfo> pendingResults, - List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) + List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, + String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); @@ -638,6 +646,14 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeTypedList(pendingNewIntents); data.writeInt(notResumed ? 1 : 0); data.writeInt(isForward ? 1 : 0); + data.writeString(profileName); + if (profileFd != null) { + data.writeInt(1); + profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + } else { + data.writeInt(0); + } + data.writeInt(autoStopProfiler ? 1 : 0); mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); @@ -793,8 +809,9 @@ class ApplicationThreadProxy implements IApplicationThread { } public final void bindApplication(String packageName, ApplicationInfo info, - List<ProviderInfo> providers, ComponentName testName, - String profileName, Bundle testArgs, IInstrumentationWatcher testWatcher, int debugMode, + List<ProviderInfo> providers, ComponentName testName, String profileName, + ParcelFileDescriptor profileFd, boolean autoStopProfiler, Bundle testArgs, + IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) throws RemoteException { Parcel data = Parcel.obtain(); @@ -809,6 +826,13 @@ class ApplicationThreadProxy implements IApplicationThread { testName.writeToParcel(data, 0); } data.writeString(profileName); + if (profileFd != null) { + data.writeInt(1); + profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + } else { + data.writeInt(0); + } + data.writeInt(autoStopProfiler ? 1 : 0); data.writeBundle(testArgs); data.writeStrongInterface(testWatcher); data.writeInt(debugMode); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index b1b0583..49f8449 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -84,11 +84,13 @@ public interface IActivityManager extends IInterface { public int startActivity(IApplicationThread caller, Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, - boolean onlyIfNeeded, boolean debug) throws RemoteException; + boolean onlyIfNeeded, boolean debug, String profileFile, + ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException; public WaitResult startActivityAndWait(IApplicationThread caller, Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, - boolean onlyIfNeeded, boolean debug) throws RemoteException; + boolean onlyIfNeeded, boolean debug, String profileFile, + ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException; public int startActivityWithConfig(IApplicationThread caller, Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, @@ -118,7 +120,8 @@ public interface IActivityManager extends IInterface { public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException; public void attachApplication(IApplicationThread app) throws RemoteException; /* oneway */ - public void activityIdle(IBinder token, Configuration config) throws RemoteException; + public void activityIdle(IBinder token, Configuration config, + boolean stopProfiling) throws RemoteException; public void activityPaused(IBinder token) throws RemoteException; /* oneway */ public void activityStopped(IBinder token, Bundle state, diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 3a8eb28..9ae5ab1 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -55,7 +55,8 @@ public interface IApplicationThread extends IInterface { void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, CompatibilityInfo compatInfo, Bundle state, List<ResultInfo> pendingResults, - List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) + List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, + String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException; void scheduleRelaunchActivity(IBinder token, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, int configChanges, @@ -86,7 +87,8 @@ public interface IApplicationThread extends IInterface { static final int DEBUG_ON = 1; static final int DEBUG_WAIT = 2; void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers, - ComponentName testName, String profileName, Bundle testArguments, + ComponentName testName, String profileName, ParcelFileDescriptor profileFd, + boolean autoStopProfiler, Bundle testArguments, IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) throws RemoteException; diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index f99b420..f3bc495 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -1379,7 +1379,7 @@ public class Instrumentation { .startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), null, 0, token, target != null ? target.mEmbeddedID : null, - requestCode, false, false); + requestCode, false, false, null, null, false); checkStartActivityResult(result, intent); } catch (RemoteException e) { } @@ -1475,7 +1475,7 @@ public class Instrumentation { .startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), null, 0, token, target != null ? target.mWho : null, - requestCode, false, false); + requestCode, false, false, null, null, false); checkStartActivityResult(result, intent); } catch (RemoteException e) { } diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 3ea3f56..ac15d9c 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -129,6 +129,16 @@ public class ParcelFileDescriptor implements Parcelable { } /** + * Create a new ParcelFileDescriptor that is a dup of the existing + * FileDescriptor. This obeys standard POSIX semantics, where the + * new file descriptor shared state such as file position with the + * original file descriptor. + */ + public ParcelFileDescriptor dup() throws IOException { + return dup(getFileDescriptor()); + } + + /** * Create a new ParcelFileDescriptor from a raw native fd. The new * ParcelFileDescriptor holds a dup of the original fd passed in here, * so you must still close that fd as well as the new ParcelFileDescriptor. diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index ff8dc92..f88b311 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -3229,7 +3229,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { int result = ActivityManagerNative.getDefault() .startActivity(null, dock, dock.resolveTypeIfNeeded(mContext.getContentResolver()), - null, 0, null, null, 0, true /* onlyIfNeeded*/, false); + null, 0, null, null, 0, true /* onlyIfNeeded*/, false, + null, null, false); if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { return false; } @@ -3238,7 +3239,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { int result = ActivityManagerNative.getDefault() .startActivity(null, mHomeIntent, mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), - null, 0, null, null, 0, true /* onlyIfNeeded*/, false); + null, 0, null, null, 0, true /* onlyIfNeeded*/, false, + null, null, false); if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { return false; } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index d5a1b8f..33a4e51 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -738,6 +738,12 @@ public final class ActivityManagerService extends ActivityManagerNative boolean mOrigWaitForDebugger = false; boolean mAlwaysFinishActivities = false; IActivityController mController = null; + String mProfileApp = null; + ProcessRecord mProfileProc = null; + String mProfileFile; + ParcelFileDescriptor mProfileFd; + int mProfileType = 0; + boolean mAutoStopProfiler = false; final RemoteCallbackList<IActivityWatcher> mWatchers = new RemoteCallbackList<IActivityWatcher>(); @@ -2090,22 +2096,24 @@ public final class ActivityManagerService extends ActivityManagerNative public final int startActivity(IApplicationThread caller, Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, - String resultWho, int requestCode, boolean onlyIfNeeded, - boolean debug) { + String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug, + String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType, grantedUriPermissions, grantedMode, resultTo, resultWho, - requestCode, onlyIfNeeded, debug, null, null); + requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler, + null, null); } public final WaitResult startActivityAndWait(IApplicationThread caller, Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, - String resultWho, int requestCode, boolean onlyIfNeeded, - boolean debug) { + String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug, + String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { WaitResult res = new WaitResult(); mMainStack.startActivityMayWait(caller, -1, intent, resolvedType, grantedUriPermissions, grantedMode, resultTo, resultWho, - requestCode, onlyIfNeeded, debug, res, null); + requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler, + res, null); return res; } @@ -2116,7 +2124,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean debug, Configuration config) { return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType, grantedUriPermissions, grantedMode, resultTo, resultWho, - requestCode, onlyIfNeeded, debug, null, config); + requestCode, onlyIfNeeded, debug, null, null, false, null, config); } public int startActivityIntentSender(IApplicationThread caller, @@ -2255,7 +2263,8 @@ public final class ActivityManagerService extends ActivityManagerNative } return mMainStack.startActivityMayWait(null, uid, intent, resolvedType, - null, 0, resultTo, resultWho, requestCode, onlyIfNeeded, false, null, null); + null, 0, resultTo, resultWho, requestCode, onlyIfNeeded, false, + null, null, false, null, null); } public final int startActivities(IApplicationThread caller, @@ -2543,6 +2552,10 @@ public final class ActivityManagerService extends ActivityManagerNative mLruProcesses.remove(app); } + if (mProfileProc == app) { + clearProfilerLocked(); + } + // Just in case... if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) { if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity); @@ -3549,7 +3562,16 @@ public final class ActivityManagerService extends ActivityManagerNative mWaitForDebugger = mOrigWaitForDebugger; } } - + String profileFile = app.instrumentationProfileFile; + ParcelFileDescriptor profileFd = null; + boolean profileAutoStop = false; + if (mProfileApp != null && mProfileApp.equals(processName)) { + mProfileProc = app; + profileFile = mProfileFile; + profileFd = mProfileFd; + profileAutoStop = mAutoStopProfiler; + } + // If the app is being launched for restore or full backup, set it up specially boolean isRestrictedBackupMode = false; if (mBackupTarget != null && mBackupAppName.equals(processName)) { @@ -3569,8 +3591,11 @@ public final class ActivityManagerService extends ActivityManagerNative ApplicationInfo appInfo = app.instrumentationInfo != null ? app.instrumentationInfo : app.info; app.compat = compatibilityInfoForPackageLocked(appInfo); + if (profileFd != null) { + profileFd = profileFd.dup(); + } thread.bindApplication(processName, appInfo, providers, - app.instrumentationClass, app.instrumentationProfileFile, + app.instrumentationClass, profileFile, profileFd, profileAutoStop, app.instrumentationArguments, app.instrumentationWatcher, testMode, isRestrictedBackupMode || !normalMode, mConfiguration, app.compat, getCommonServicesLocked(), @@ -3697,9 +3722,22 @@ public final class ActivityManagerService extends ActivityManagerNative } } - public final void activityIdle(IBinder token, Configuration config) { + public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) { final long origId = Binder.clearCallingIdentity(); - mMainStack.activityIdleInternal(token, false, config); + ActivityRecord r = mMainStack.activityIdleInternal(token, false, config); + if (stopProfiling) { + synchronized (this) { + if (mProfileProc == r.app) { + if (mProfileFd != null) { + try { + mProfileFd.close(); + } catch (IOException e) { + } + clearProfilerLocked(); + } + } + } + } Binder.restoreCallingIdentity(origId); } @@ -6147,6 +6185,30 @@ public final class ActivityManagerService extends ActivityManagerNative } } + void setProfileApp(ApplicationInfo app, String processName, String profileFile, + ParcelFileDescriptor profileFd, boolean autoStopProfiler) { + synchronized (this) { + boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); + if (!isDebuggable) { + if ((app.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) { + throw new SecurityException("Process not debuggable: " + app.packageName); + } + } + mProfileApp = processName; + mProfileFile = profileFile; + if (mProfileFd != null) { + try { + mProfileFd.close(); + } catch (IOException e) { + } + mProfileFd = null; + } + mProfileFd = profileFd; + mProfileType = 0; + mAutoStopProfiler = autoStopProfiler; + } + } + public void setAlwaysFinish(boolean enabled) { enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH, "setAlwaysFinish()"); @@ -7886,6 +7948,13 @@ public final class ActivityManagerService extends ActivityManagerNative + " mDebugTransient=" + mDebugTransient + " mOrigWaitForDebugger=" + mOrigWaitForDebugger); } + if (mProfileApp != null || mProfileProc != null || mProfileFile != null + || mProfileFd != null) { + pw.println(" mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc); + pw.println(" mProfileFile=" + mProfileFile + " mProfileFd=" + mProfileFd); + pw.println(" mProfileType=" + mProfileType + " mAutoStopProfiler=" + + mAutoStopProfiler); + } if (mAlwaysFinishActivities || mController != null) { pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities + " mController=" + mController); @@ -13577,6 +13646,37 @@ public final class ActivityManagerService extends ActivityManagerNative } } + private void stopProfilerLocked(ProcessRecord proc, String path, int profileType) { + if (proc == null || proc == mProfileProc) { + proc = mProfileProc; + path = mProfileFile; + profileType = mProfileType; + clearProfilerLocked(); + } + if (proc == null) { + return; + } + try { + proc.thread.profilerControl(false, path, null, profileType); + } catch (RemoteException e) { + throw new IllegalStateException("Process disappeared"); + } + } + + private void clearProfilerLocked() { + if (mProfileFd != null) { + try { + mProfileFd.close(); + } catch (IOException e) { + } + } + mProfileApp = null; + mProfileProc = null; + mProfileFile = null; + mProfileType = 0; + mAutoStopProfiler = false; + } + public boolean profileControl(String process, boolean start, String path, ParcelFileDescriptor fd, int profileType) throws RemoteException { @@ -13589,42 +13689,58 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException("Requires permission " + android.Manifest.permission.SET_ACTIVITY_WATCHER); } - + if (start && fd == null) { throw new IllegalArgumentException("null fd"); } - + ProcessRecord proc = null; - try { - int pid = Integer.parseInt(process); - synchronized (mPidsSelfLocked) { - proc = mPidsSelfLocked.get(pid); + if (process != null) { + try { + int pid = Integer.parseInt(process); + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(pid); + } + } catch (NumberFormatException e) { } - } catch (NumberFormatException e) { - } - - if (proc == null) { - HashMap<String, SparseArray<ProcessRecord>> all - = mProcessNames.getMap(); - SparseArray<ProcessRecord> procs = all.get(process); - if (procs != null && procs.size() > 0) { - proc = procs.valueAt(0); + + if (proc == null) { + HashMap<String, SparseArray<ProcessRecord>> all + = mProcessNames.getMap(); + SparseArray<ProcessRecord> procs = all.get(process); + if (procs != null && procs.size() > 0) { + proc = procs.valueAt(0); + } } } - - if (proc == null || proc.thread == null) { + + if (start && (proc == null || proc.thread == null)) { throw new IllegalArgumentException("Unknown process: " + process); } - - boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); - if (!isDebuggable) { - if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) { - throw new SecurityException("Process not debuggable: " + proc); + + if (start) { + stopProfilerLocked(null, null, 0); + setProfileApp(proc.info, proc.processName, path, fd, false); + mProfileProc = proc; + mProfileType = profileType; + try { + fd = fd.dup(); + } catch (IOException e) { + fd = null; + } + proc.thread.profilerControl(start, path, fd, profileType); + fd = null; + mProfileFd = null; + } else { + stopProfilerLocked(proc, path, profileType); + if (fd != null) { + try { + fd.close(); + } catch (IOException e) { + } } } - - proc.thread.profilerControl(start, path, fd, profileType); - fd = null; + return true; } } catch (RemoteException e) { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index ee0937d..6f0779f 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -56,6 +56,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; @@ -64,6 +65,7 @@ import android.util.Log; import android.util.Slog; import android.view.WindowManagerPolicy; +import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Iterator; @@ -561,12 +563,31 @@ final class ActivityStack { r.forceNewConfig = false; showAskCompatModeDialogLocked(r); r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); + String profileFile = null; + ParcelFileDescriptor profileFd = null; + boolean profileAutoStop = false; + if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) { + if (mService.mProfileProc == null || mService.mProfileProc == app) { + mService.mProfileProc = app; + profileFile = mService.mProfileFile; + profileFd = mService.mProfileFd; + profileAutoStop = mService.mAutoStopProfiler; + } + } app.hasShownUi = true; app.pendingUiClean = true; + if (profileFd != null) { + try { + profileFd = profileFd.dup(); + } catch (IOException e) { + profileFd = null; + } + } app.thread.scheduleLaunchActivity(new Intent(r.intent), r, System.identityHashCode(r), r.info, r.compat, r.icicle, results, newIntents, !andResume, - mService.isNextTransitionForward()); + mService.isNextTransitionForward(), profileFile, profileFd, + profileAutoStop); if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { // This may be a heavy-weight process! Note that the package @@ -2669,7 +2690,8 @@ final class ActivityStack { return START_SUCCESS; } - ActivityInfo resolveActivity(Intent intent, String resolvedType, boolean debug) { + ActivityInfo resolveActivity(Intent intent, String resolvedType, boolean debug, + String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { // Collect information about the target of the Intent. ActivityInfo aInfo; try { @@ -2697,6 +2719,13 @@ final class ActivityStack { mService.setDebugApp(aInfo.processName, true, false); } } + + if (profileFile != null) { + if (!aInfo.processName.equals("system")) { + mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, + profileFile, profileFd, autoStopProfiler); + } + } } return aInfo; } @@ -2705,7 +2734,8 @@ final class ActivityStack { Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, boolean onlyIfNeeded, - boolean debug, WaitResult outResult, Configuration config) { + boolean debug, String profileFile, ParcelFileDescriptor profileFd, + boolean autoStopProfiler, WaitResult outResult, Configuration config) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -2717,7 +2747,8 @@ final class ActivityStack { intent = new Intent(intent); // Collect information about the target of the Intent. - ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug); + ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug, + profileFile, profileFd, autoStopProfiler); synchronized (mService) { int callingPid; @@ -2903,7 +2934,8 @@ final class ActivityStack { intent = new Intent(intent); // Collect information about the target of the Intent. - ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false); + ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false, + null, null, false); if (mMainStack && aInfo != null && (aInfo.applicationInfo.flags & ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { @@ -3069,10 +3101,12 @@ final class ActivityStack { return stops; } - final void activityIdleInternal(IBinder token, boolean fromTimeout, + final ActivityRecord activityIdleInternal(IBinder token, boolean fromTimeout, Configuration config) { if (localLOGV) Slog.v(TAG, "Activity idle: " + token); + ActivityRecord res = null; + ArrayList<ActivityRecord> stops = null; ArrayList<ActivityRecord> finishes = null; ArrayList<ActivityRecord> thumbnails = null; @@ -3092,6 +3126,7 @@ final class ActivityStack { int index = indexOfTokenLocked(token); if (index >= 0) { ActivityRecord r = mHistory.get(index); + res = r; if (fromTimeout) { reportActivityLaunchedLocked(fromTimeout, r, -1, -1); @@ -3207,6 +3242,8 @@ final class ActivityStack { if (enableScreen) { mService.enableScreenAfterBoot(); } + + return res; } /** |