summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2011-08-15 17:40:28 -0700
committerDianne Hackborn <hackbod@google.com>2011-08-15 17:55:57 -0700
commit62f20ecf492d2b29881bba307c79ff55e68760e6 (patch)
tree58ea602138a28fb3555368900acbad6219ae2de2
parent0f2da17a9523fc40bceb5209cabd044df648e98e (diff)
downloadframeworks_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.java41
-rw-r--r--core/java/android/app/Activity.java3
-rw-r--r--core/java/android/app/ActivityManagerNative.java41
-rw-r--r--core/java/android/app/ActivityThread.java106
-rw-r--r--core/java/android/app/ApplicationThreadNative.java34
-rw-r--r--core/java/android/app/IActivityManager.java9
-rw-r--r--core/java/android/app/IApplicationThread.java6
-rw-r--r--core/java/android/app/Instrumentation.java4
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java10
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java6
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java190
-rw-r--r--services/java/com/android/server/am/ActivityStack.java49
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;
}
/**