Add new am option to profile the launching of an activity.
Change-Id: Ie71a8043eafe41f53a0b3dbb5170276d87acbc9b
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 @@
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 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 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 @@
}
}
+ 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 @@
+ " 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 @@
}
}
+ 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 @@
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.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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
if (enableScreen) {
mService.enableScreenAfterBoot();
}
+
+ return res;
}
/**