Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 029853ac authored by Mythri Alle's avatar Mythri Alle
Browse files

Extend am profile command to also collect lowoverhead traces.

Low overhead tracing is an experimental feature that is only enabled
when com.android.art.flags.Flags.alwaysEnableProfileCode is set. If this
isn't set we just log an error and ignore the request for tracing.

Usage:
adb shell am profile lowoverhead start <pid>
adb shell am profile lowoverhead stop <pid> [<path/to/file>]

File is optional when stopping the trace. If no file is provided then
trace data is simply discarded.

Test: manual test by capturing a trace
Bug: 352518093
Change-Id: Ie1ab526e0827b099a0d2f14ee170a2e0aca39d34
parent c036a668
Loading
Loading
Loading
Loading
+32 −9
Original line number Diff line number Diff line
@@ -6859,21 +6859,44 @@ public final class ActivityThread extends ClientTransactionHandler

    final void handleProfilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) {
        if (start) {
            try {
            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();
                    }
            }
        } 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;
+6 −0
Original line number Diff line number Diff line
@@ -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
+7 −4
Original line number Diff line number Diff line
@@ -7590,7 +7590,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;
@@ -7606,7 +7606,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                            + "and not profileable by shell: " + app.packageName);
                }
            }
            mAppProfiler.setProfileAppLPf(processName, profilerInfo);
            mAppProfiler.setProfileAppLPf(processName, profilerInfo, profileType);
        }
    }
@@ -17860,7 +17860,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");
        }
@@ -19476,7 +19477,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();
                }
+19 −2
Original line number Diff line number Diff line
@@ -1069,7 +1069,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;
@@ -1111,6 +1111,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;
@@ -1130,7 +1142,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) {
+47 −28
Original line number Diff line number Diff line
@@ -1990,7 +1990,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;
@@ -2004,7 +2004,7 @@ public class AppProfiler {
            return;
        }
        try {
            thread.profilerControl(false, null, profileType);
            thread.profilerControl(false, profilerInfo, profileType);
        } catch (RemoteException e) {
            throw new IllegalStateException("Process disappeared");
        }
@@ -2039,19 +2039,27 @@ 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;

                ParcelFileDescriptor fd = null;
                if (needsFile) {
                    fd = profilerInfo.profileFd;
                    try {
                        fd = fd.dup();
                    } catch (IOException e) {
                        fd = null;
                    }
                    profilerInfo.profileFd = fd;
                }

                proc.mProfile.getThread().profilerControl(start, profilerInfo, profileType);

                if (needsFile) {
                    fd = null;
                    try {
                        mProfileData.getProfilerInfo().profileFd.close();
@@ -2066,14 +2074,23 @@ public class AppProfiler {
                        //       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;
@@ -2090,7 +2107,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) {
@@ -2101,8 +2118,10 @@ public class AppProfiler {
                }
            }
        }
        if (profilerInfo != null) {
            mProfileData.setProfilerInfo(new ProfilerInfo(profilerInfo));
        mProfileType = 0;
        }
        mProfileType = profileType;
    }

    @GuardedBy("mProfilerLock")