Add sample profiling option to am.

Also bundles all profiling options into a class.

Bug: 17040932
Change-Id: I85d675ee1494bdc7308caffdf94145d27c996e9d
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e2a6534..e93dac6 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -37,6 +37,7 @@
 import android.app.IActivityContainer;
 import android.app.IActivityContainerCallback;
 import android.app.IAppTask;
+import android.app.ProfilerInfo;
 import android.app.admin.DevicePolicyManager;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal;
@@ -1050,8 +1051,9 @@
     ProcessRecord mProfileProc = null;
     String mProfileFile;
     ParcelFileDescriptor mProfileFd;
-    int mProfileType = 0;
+    int mSamplingInterval = 0;
     boolean mAutoStopProfiler = false;
+    int mProfileType = 0;
     String mOpenGlTraceApp = null;
 
     static class ProcessChangeItem {
@@ -3443,33 +3445,30 @@
 
     @Override
     public final int startActivity(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo,
-            String resultWho, int requestCode, int startFlags,
-            String profileFile, ParcelFileDescriptor profileFd, Bundle options) {
+            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
         return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
-                resultWho, requestCode,
-                startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId());
+            resultWho, requestCode, startFlags, profilerInfo, options,
+            UserHandle.getCallingUserId());
     }
 
     @Override
     public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo,
-            String resultWho, int requestCode, int startFlags,
-            String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) {
+            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
         enforceNotIsolatedCaller("startActivity");
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, ALLOW_FULL_ONLY, "startActivity", null);
         // TODO: Switch to user app stacks here.
-        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
-                null, null, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
-                null, null, options, userId, null, null);
+        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
+                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
+                profilerInfo, null, null, options, userId, null, null);
     }
 
     @Override
     public final int startActivityAsCaller(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo,
-            String resultWho, int requestCode, int startFlags,
-            String profileFile, ParcelFileDescriptor profileFd, Bundle options) {
+            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
 
         // This is very dangerous -- it allows you to perform a start activity (including
         // permission grants) as any app that may launch one of your own activities.  So
@@ -3510,9 +3509,8 @@
         // TODO: Switch to user app stacks here.
         try {
             int ret = mStackSupervisor.startActivityMayWait(null, targetUid, targetPackage, intent,
-                    resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
-                    null, null, null, null, options, UserHandle.getUserId(sourceRecord.app.uid),
-                    null, null);
+                    resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null,
+                    null, null, options, UserHandle.getUserId(sourceRecord.app.uid), null, null);
             return ret;
         } catch (SecurityException e) {
             // XXX need to figure out how to propagate to original app.
@@ -3532,32 +3530,30 @@
 
     @Override
     public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo,
-            String resultWho, int requestCode, int startFlags, String profileFile,
-            ParcelFileDescriptor profileFd, Bundle options, int userId) {
+            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
         enforceNotIsolatedCaller("startActivityAndWait");
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
         WaitResult res = new WaitResult();
         // TODO: Switch to user app stacks here.
         mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
-                null, null, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
-                res, null, options, userId, null, null);
+                null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,
+                options, userId, null, null);
         return res;
     }
 
     @Override
     public final int startActivityWithConfig(IApplicationThread caller, String callingPackage,
-            Intent intent, String resolvedType, IBinder resultTo,
-            String resultWho, int requestCode, int startFlags, Configuration config,
-            Bundle options, int userId) {
+            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
+            int startFlags, Configuration config, Bundle options, int userId) {
         enforceNotIsolatedCaller("startActivityWithConfig");
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, ALLOW_FULL_ONLY, "startActivityWithConfig", null);
         // TODO: Switch to user app stacks here.
         int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
-                null, null, null, config, options, userId, null, null);
+                null, null, config, options, userId, null, null);
         return ret;
     }
 
@@ -3596,8 +3592,8 @@
     @Override
     public int startVoiceActivity(String callingPackage, int callingPid, int callingUid,
             Intent intent, String resolvedType, IVoiceInteractionSession session,
-            IVoiceInteractor interactor, int startFlags, String profileFile,
-            ParcelFileDescriptor profileFd, Bundle options, int userId) {
+            IVoiceInteractor interactor, int startFlags, ProfilerInfo profilerInfo,
+            Bundle options, int userId) {
         if (checkCallingPermission(Manifest.permission.BIND_VOICE_INTERACTION)
                 != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: startVoiceActivity() from pid="
@@ -3614,8 +3610,8 @@
                 false, ALLOW_FULL_ONLY, "startVoiceActivity", null);
         // TODO: Switch to user app stacks here.
         return mStackSupervisor.startActivityMayWait(null, callingUid, callingPackage, intent,
-                resolvedType, session, interactor, null, null, 0, startFlags,
-                profileFile, profileFd, null, null, options, userId, null, null);
+                resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null,
+                null, options, userId, null, null);
     }
 
     @Override
@@ -3767,7 +3763,7 @@
         // TODO: Switch to user app stacks here.
         int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent,
                 resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
-                null, null, null, null, options, userId, container, inTask);
+                null, null, null, options, userId, container, inTask);
         return ret;
     }
 
@@ -5613,11 +5609,13 @@
             }
             String profileFile = app.instrumentationProfileFile;
             ParcelFileDescriptor profileFd = null;
+            int samplingInterval = 0;
             boolean profileAutoStop = false;
             if (mProfileApp != null && mProfileApp.equals(processName)) {
                 mProfileProc = app;
                 profileFile = mProfileFile;
                 profileFd = mProfileFd;
+                samplingInterval = mSamplingInterval;
                 profileAutoStop = mAutoStopProfiler;
             }
             boolean enableOpenGlTrace = false;
@@ -5648,9 +5646,10 @@
             if (profileFd != null) {
                 profileFd = profileFd.dup();
             }
-            thread.bindApplication(processName, appInfo, providers,
-                    app.instrumentationClass, profileFile, profileFd, profileAutoStop,
-                    app.instrumentationArguments, app.instrumentationWatcher,
+            ProfilerInfo profilerInfo = profileFile == null ? null
+                    : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
+            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
+                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                     app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                     isRestrictedBackupMode || !normalMode, app.persistent,
                     new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
@@ -9695,8 +9694,7 @@
         }
     }
 
-    void setProfileApp(ApplicationInfo app, String processName, String profileFile,
-            ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+    void setProfileApp(ApplicationInfo app, String processName, ProfilerInfo profilerInfo) {
         synchronized (this) {
             boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
             if (!isDebuggable) {
@@ -9705,7 +9703,7 @@
                 }
             }
             mProfileApp = processName;
-            mProfileFile = profileFile;
+            mProfileFile = profilerInfo.profileFile;
             if (mProfileFd != null) {
                 try {
                     mProfileFd.close();
@@ -9713,9 +9711,10 @@
                 }
                 mProfileFd = null;
             }
-            mProfileFd = profileFd;
+            mProfileFd = profilerInfo.profileFd;
+            mSamplingInterval = profilerInfo.samplingInterval;
+            mAutoStopProfiler = profilerInfo.autoStopProfiler;
             mProfileType = 0;
-            mAutoStopProfiler = autoStopProfiler;
         }
     }
 
@@ -9727,7 +9726,7 @@
         Settings.Global.putInt(
                 mContext.getContentResolver(),
                 Settings.Global.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
-        
+
         synchronized (this) {
             mAlwaysFinishActivities = enabled;
         }
@@ -12303,8 +12302,9 @@
                 }
                 pw.println("  mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc);
                 pw.println("  mProfileFile=" + mProfileFile + " mProfileFd=" + mProfileFd);
-                pw.println("  mProfileType=" + mProfileType + " mAutoStopProfiler="
+                pw.println("  mSamplingInterval=" + mSamplingInterval + " mAutoStopProfiler="
                         + mAutoStopProfiler);
+                pw.println("  mProfileType=" + mProfileType);
             }
         }
         if (dumpPackage == null) {
@@ -17310,10 +17310,9 @@
         }
     }
 
-    private void stopProfilerLocked(ProcessRecord proc, String path, int profileType) {
+    private void stopProfilerLocked(ProcessRecord proc, int profileType) {
         if (proc == null || proc == mProfileProc) {
             proc = mProfileProc;
-            path = mProfileFile;
             profileType = mProfileType;
             clearProfilerLocked();
         }
@@ -17321,7 +17320,7 @@
             return;
         }
         try {
-            proc.thread.profilerControl(false, path, null, profileType);
+            proc.thread.profilerControl(false, null, profileType);
         } catch (RemoteException e) {
             throw new IllegalStateException("Process disappeared");
         }
@@ -17339,10 +17338,11 @@
         mProfileFile = null;
         mProfileType = 0;
         mAutoStopProfiler = false;
+        mSamplingInterval = 0;
     }
 
     public boolean profileControl(String process, int userId, boolean start,
-            String path, ParcelFileDescriptor fd, int profileType) throws RemoteException {
+            ProfilerInfo profilerInfo, int profileType) throws RemoteException {
 
         try {
             synchronized (this) {
@@ -17354,8 +17354,8 @@
                             + android.Manifest.permission.SET_ACTIVITY_WATCHER);
                 }
 
-                if (start && fd == null) {
-                    throw new IllegalArgumentException("null fd");
+                if (start && (profilerInfo == null || profilerInfo.profileFd == null)) {
+                    throw new IllegalArgumentException("null profile info or fd");
                 }
 
                 ProcessRecord proc = null;
@@ -17368,23 +17368,25 @@
                 }
 
                 if (start) {
-                    stopProfilerLocked(null, null, 0);
-                    setProfileApp(proc.info, proc.processName, path, fd, false);
+                    stopProfilerLocked(null, 0);
+                    setProfileApp(proc.info, proc.processName, profilerInfo);
                     mProfileProc = proc;
                     mProfileType = profileType;
+                    ParcelFileDescriptor fd = profilerInfo.profileFd;
                     try {
                         fd = fd.dup();
                     } catch (IOException e) {
                         fd = null;
                     }
-                    proc.thread.profilerControl(start, path, fd, profileType);
+                    profilerInfo.profileFd = fd;
+                    proc.thread.profilerControl(start, profilerInfo, profileType);
                     fd = null;
                     mProfileFd = null;
                 } else {
-                    stopProfilerLocked(proc, path, profileType);
-                    if (fd != null) {
+                    stopProfilerLocked(proc, profileType);
+                    if (profilerInfo != null && profilerInfo.profileFd != null) {
                         try {
-                            fd.close();
+                            profilerInfo.profileFd.close();
                         } catch (IOException e) {
                         }
                     }
@@ -17395,9 +17397,9 @@
         } catch (RemoteException e) {
             throw new IllegalStateException("Process disappeared");
         } finally {
-            if (fd != null) {
+            if (profilerInfo != null && profilerInfo.profileFd != null) {
                 try {
-                    fd.close();
+                    profilerInfo.profileFd.close();
                 } catch (IOException e) {
                 }
             }
@@ -18407,7 +18409,7 @@
             }
             return mStackSupervisor.startActivityMayWait(appThread, -1, callingPackage, intent,
                     resolvedType, null, null, null, null, 0, 0, null, null,
-                    null, null, options, callingUser, null, tr);
+                    null, options, callingUser, null, tr);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 066ec68..77b4cc9 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1187,7 +1187,7 @@
 
         final ActivityManagerService service = stackSupervisor.mService;
         final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null,
-                null, userId);
+                userId);
         if (aInfo == null) {
             throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent +
                     " resolvedType=" + resolvedType);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a9898ee..6b5c931 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -45,6 +45,7 @@
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
 import android.app.PendingIntent;
+import android.app.ProfilerInfo;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.IActivityManager.WaitResult;
 import android.app.ResultInfo;
@@ -734,7 +735,7 @@
     }
 
     ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
-            String profileFile, ParcelFileDescriptor profileFd, int userId) {
+            ProfilerInfo profilerInfo, int userId) {
         // Collect information about the target of the Intent.
         ActivityInfo aInfo;
         try {
@@ -769,11 +770,9 @@
                 }
             }
 
-            if (profileFile != null) {
+            if (profilerInfo != null) {
                 if (!aInfo.processName.equals("system")) {
-                    mService.setProfileApp(aInfo.applicationInfo, aInfo.processName,
-                            profileFile, profileFd,
-                            (startFlags&ActivityManager.START_FLAG_AUTO_STOP_PROFILER) != 0);
+                    mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
                 }
             }
         }
@@ -789,8 +788,8 @@
     final int startActivityMayWait(IApplicationThread caller, int callingUid,
             String callingPackage, Intent intent, String resolvedType,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile,
-            ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
+            IBinder resultTo, String resultWho, int requestCode, int startFlags,
+            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
             Bundle options, int userId, IActivityContainer iContainer, TaskRecord inTask) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors()) {
@@ -803,7 +802,7 @@
 
         // Collect information about the target of the Intent.
         ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
-                profileFile, profileFd, userId);
+                profilerInfo, userId);
 
         ActivityContainer container = (ActivityContainer)iContainer;
         synchronized (mService) {
@@ -996,8 +995,7 @@
                     intent = new Intent(intent);
 
                     // Collect information about the target of the Intent.
-                    ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i],
-                            0, null, null, userId);
+                    ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], 0, null, userId);
                     // TODO: New, check if this is correct
                     aInfo = mService.getActivityInfoForUser(aInfo, userId);
 
@@ -1100,13 +1098,11 @@
             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;
@@ -1125,13 +1121,15 @@
                 }
             }
 
+            ProfilerInfo profilerInfo = profileFile != null
+                    ? new ProfilerInfo(profileFile, profileFd, mService.mSamplingInterval,
+                    mService.mAutoStopProfiler) : null;
             app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
-                    System.identityHashCode(r), r.info,
-                    new Configuration(mService.mConfiguration), r.compat, r.task.voiceInteractor,
-                    app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume,
-                    mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop
-            );
+                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
+                    r.compat, r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState,
+                    results, newIntents, !andResume, mService.isNextTransitionForward(),
+                    profilerInfo);
 
             if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
                 // This may be a heavy-weight process!  Note that the package
@@ -3625,8 +3623,8 @@
                     && "content".equals(intent.getData().getScheme())) {
                 mimeType = mService.getProviderMimeType(intent.getData(), userId);
             }
-            return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null, 0, 0, null,
-                    null, null, null, null, userId, this, null);
+            return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null, 0,
+                    0, null, null, null, null, userId, this, null);
         }
 
         @Override
@@ -3652,7 +3650,7 @@
                     resolvedType = mService.getProviderMimeType(intent.getData(), userId);
                 }
             }
-            ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, null, userId);
+            ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, userId);
             if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
                 throw new SecurityException(
                         "Attempt to embed activity that has not set allowEmbedded=\"true\"");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index c0e536a..b36b611 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -253,7 +253,7 @@
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
             return mAm.startVoiceActivity(mComponent.getPackageName(), callingPid, callingUid,
                     intent, resolvedType, mActiveSession.mSession, mActiveSession.mInteractor,
-                    0, null, null, null, mUser);
+                    0, null, null, mUser);
         } catch (RemoteException e) {
             throw new IllegalStateException("Unexpected remote error", e);
         }