diff options
5 files changed, 111 insertions, 43 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f8186d68e210..3c1cce973b3a 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -6995,21 +6995,44 @@ public final class ActivityThread extends ClientTransactionHandler final void handleProfilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) { if (start) { - try { - switch (profileType) { - default: + switch (profileType) { + case ProfilerInfo.PROFILE_TYPE_LOW_OVERHEAD: + if (!com.android.art.flags.Flags.alwaysEnableProfileCode()) { + Slog.w(TAG, "Low overhead tracing feature is not enabled"); + break; + } + VMDebug.startLowOverheadTrace(); + break; + default: + try { mProfiler.setProfiler(profilerInfo); mProfiler.startProfiling(); break; - } - } catch (RuntimeException e) { - Slog.w(TAG, "Profiling failed on path " + profilerInfo.profileFile - + " -- can the process access this path?"); - } finally { - profilerInfo.closeFd(); + } catch (RuntimeException e) { + Slog.w(TAG, "Profiling failed on path " + profilerInfo.profileFile + + " -- can the process access this path?"); + } finally { + profilerInfo.closeFd(); + } } } else { switch (profileType) { + case ProfilerInfo.PROFILE_TYPE_LOW_OVERHEAD: + if (!com.android.art.flags.Flags.alwaysEnableProfileCode()) { + if (profilerInfo != null) { + profilerInfo.closeFd(); + } + Slog.w(TAG, "Low overhead tracing feature is not enabled"); + break; + } + if (profilerInfo != null) { + FileDescriptor fd = profilerInfo.profileFd.getFileDescriptor(); + VMDebug.TraceDestination dst = + VMDebug.TraceDestination.fromFileDescriptor(fd); + VMDebug.dumpLowOverheadTrace(dst); + } + VMDebug.stopLowOverheadTrace(); + break; default: mProfiler.stopProfiling(); break; diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java index bcae22a38f9e..0348b6de9964 100644 --- a/core/java/android/app/ProfilerInfo.java +++ b/core/java/android/app/ProfilerInfo.java @@ -32,6 +32,12 @@ import java.util.Objects; * {@hide} */ public class ProfilerInfo implements Parcelable { + // Regular profiling which provides different modes of profiling at some performance cost. + public static final int PROFILE_TYPE_REGULAR = 0; + + // Low overhead profiling that captures a simple sliding window of past events. + public static final int PROFILE_TYPE_LOW_OVERHEAD = 1; + // Version of the profiler output public static final int OUTPUT_VERSION_DEFAULT = 1; // CLOCK_TYPE_DEFAULT chooses the default used by ART. ART uses CLOCK_TYPE_DUAL by default (see diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 78dee3169161..7eca893a7035 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7553,7 +7553,7 @@ public class ActivityManagerService extends IActivityManager.Stub } void setProfileApp(ApplicationInfo app, String processName, ProfilerInfo profilerInfo, - ApplicationInfo sdkSandboxClientApp) { + ApplicationInfo sdkSandboxClientApp, int profileType) { synchronized (mAppProfiler.mProfilerLock) { if (!Build.IS_DEBUGGABLE) { boolean isAppDebuggable = (app.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; @@ -7569,7 +7569,7 @@ public class ActivityManagerService extends IActivityManager.Stub + "and not profileable by shell: " + app.packageName); } } - mAppProfiler.setProfileAppLPf(processName, profilerInfo); + mAppProfiler.setProfileAppLPf(processName, profilerInfo, profileType); } } @@ -15847,7 +15847,8 @@ public class ActivityManagerService extends IActivityManager.Stub + android.Manifest.permission.SET_ACTIVITY_WATCHER); } - if (start && (profilerInfo == null || profilerInfo.profileFd == null)) { + if (start && profileType == ProfilerInfo.PROFILE_TYPE_REGULAR + && (profilerInfo == null || profilerInfo.profileFd == null)) { throw new IllegalArgumentException("null profile info or fd"); } @@ -17490,7 +17491,9 @@ public class ActivityManagerService extends IActivityManager.Stub } if (profilerInfo != null) { - setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo, null); + // We only support normal method tracing along with app startup for now. + setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo, + null, /*profileType= */ ProfilerInfo.PROFILE_TYPE_REGULAR); } wmLock.notify(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 37d058b06b99..9a63546bf5a7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -1155,7 +1155,7 @@ final class ActivityManagerShellCommand extends ShellCommand { String profileFile = null; boolean start = false; int userId = UserHandle.USER_CURRENT; - int profileType = 0; + int profileType = ProfilerInfo.PROFILE_TYPE_REGULAR; mSamplingInterval = 0; mStreaming = false; mClockType = ProfilerInfo.CLOCK_TYPE_DEFAULT; @@ -1197,6 +1197,18 @@ final class ActivityManagerShellCommand extends ShellCommand { } } process = getNextArgRequired(); + } else if ("lowoverhead".equals(cmd)) { + // This is an experimental low overhead profiling. + profileType = ProfilerInfo.PROFILE_TYPE_LOW_OVERHEAD; + cmd = getNextArgRequired(); + if ("start".equals(cmd)) { + start = true; + } else if ("stop".equals(cmd)) { + start = false; + } else { + throw new IllegalArgumentException("Profile command not valid"); + } + process = getNextArgRequired(); } else { // Compatibility with old syntax: process is specified first. process = cmd; @@ -1216,7 +1228,12 @@ final class ActivityManagerShellCommand extends ShellCommand { ParcelFileDescriptor fd = null; ProfilerInfo profilerInfo = null; - if (start) { + // For regular method tracing profileFile should be provided with the start command. For + // low overhead method tracing the profileFile is optional and provided with the stop + // command. + if ((start && profileType == ProfilerInfo.PROFILE_TYPE_REGULAR) + || (profileType == ProfilerInfo.PROFILE_TYPE_LOW_OVERHEAD + && !start && getRemainingArgsCount() > 0)) { profileFile = getNextArgRequired(); fd = openFileForSystem(profileFile, "w"); if (fd == null) { diff --git a/services/core/java/com/android/server/am/AppProfiler.java b/services/core/java/com/android/server/am/AppProfiler.java index 4f2d69e4bb72..6b24df4a1fa8 100644 --- a/services/core/java/com/android/server/am/AppProfiler.java +++ b/services/core/java/com/android/server/am/AppProfiler.java @@ -1992,7 +1992,7 @@ public class AppProfiler { } @GuardedBy("mProfilerLock") - private void stopProfilerLPf(ProcessRecord proc, int profileType) { + private void stopProfilerLPf(ProcessRecord proc, ProfilerInfo profilerInfo, int profileType) { if (proc == null || proc == mProfileData.getProfileProc()) { proc = mProfileData.getProfileProc(); profileType = mProfileType; @@ -2006,7 +2006,7 @@ public class AppProfiler { return; } try { - thread.profilerControl(false, null, profileType); + thread.profilerControl(false, profilerInfo, profileType); } catch (RemoteException e) { throw new IllegalStateException("Process disappeared"); } @@ -2041,41 +2041,58 @@ public class AppProfiler { ProfilerInfo profilerInfo, int profileType) { try { if (start) { - stopProfilerLPf(null, 0); + boolean needsFile = (profileType == ProfilerInfo.PROFILE_TYPE_REGULAR); + stopProfilerLPf(null, null, 0); mService.setProfileApp(proc.info, proc.processName, profilerInfo, - proc.isSdkSandbox ? proc.getClientInfoForSdkSandbox() : null); + proc.isSdkSandbox ? proc.getClientInfoForSdkSandbox() : null, profileType); mProfileData.setProfileProc(proc); mProfileType = profileType; - ParcelFileDescriptor fd = profilerInfo.profileFd; - try { - fd = fd.dup(); - } catch (IOException e) { - fd = null; + + ParcelFileDescriptor fd = null; + if (needsFile) { + fd = profilerInfo.profileFd; + try { + fd = fd.dup(); + } catch (IOException e) { + fd = null; + } + profilerInfo.profileFd = fd; } - profilerInfo.profileFd = fd; + proc.mProfile.getThread().profilerControl(start, profilerInfo, profileType); - fd = null; - try { - mProfileData.getProfilerInfo().profileFd.close(); - } catch (IOException e) { - } - mProfileData.getProfilerInfo().profileFd = null; - - if (proc.getPid() == mService.MY_PID) { - // When profiling the system server itself, avoid closing the file - // descriptor, as profilerControl will not create a copy. - // Note: it is also not correct to just set profileFd to null, as the - // whole ProfilerInfo instance is passed down! - profilerInfo = null; + + if (needsFile) { + fd = null; + try { + mProfileData.getProfilerInfo().profileFd.close(); + } catch (IOException e) { + } + mProfileData.getProfilerInfo().profileFd = null; + + if (proc.getPid() == mService.MY_PID) { + // When profiling the system server itself, avoid closing the file + // descriptor, as profilerControl will not create a copy. + // Note: it is also not correct to just set profileFd to null, as the + // whole ProfilerInfo instance is passed down! + profilerInfo = null; + } } } else { - stopProfilerLPf(proc, profileType); + boolean mayNeedFile = (profileType == ProfilerInfo.PROFILE_TYPE_LOW_OVERHEAD); if (profilerInfo != null && profilerInfo.profileFd != null) { + ParcelFileDescriptor fd = profilerInfo.profileFd; try { - profilerInfo.profileFd.close(); + if (mayNeedFile) { + fd = fd.dup(); + } else { + fd.close(); + } } catch (IOException e) { + fd = null; } + profilerInfo.profileFd = fd; } + stopProfilerLPf(proc, profilerInfo, profileType); } return true; @@ -2092,7 +2109,7 @@ public class AppProfiler { } @GuardedBy("mProfilerLock") - void setProfileAppLPf(String processName, ProfilerInfo profilerInfo) { + void setProfileAppLPf(String processName, ProfilerInfo profilerInfo, int profileType) { mProfileData.setProfileApp(processName); if (mProfileData.getProfilerInfo() != null) { @@ -2103,8 +2120,10 @@ public class AppProfiler { } } } - mProfileData.setProfilerInfo(new ProfilerInfo(profilerInfo)); - mProfileType = 0; + if (profilerInfo != null) { + mProfileData.setProfilerInfo(new ProfilerInfo(profilerInfo)); + } + mProfileType = profileType; } @GuardedBy("mProfilerLock") |