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

Commit ab8a63be authored by Andreas Gampe's avatar Andreas Gampe
Browse files

ActivityThread: Attempt to attach agent with app's classloader

Try to use the app's (main) classloader when an attach-agent request
is handled. If that fails, retry without a classloader.

Add bind-application-time flag to ProfilerInfo. Use the flag to have
a second attach-agent point on app startup. Add --attach-agent-bind
to cmd activity start to expose the difference between pre-bind and
bind-time attaching.

Bug: 70901841
Test: m
Test: cts-tradefed run commandAndExit cts-dev -m CtsJvmtiAttachingHostTestCases
Change-Id: I21698ec3be43a6d095d577100b2adfb22daca7d5
parent 9cb0b520
Loading
Loading
Loading
Loading
+27 −5
Original line number Diff line number Diff line
@@ -1832,9 +1832,11 @@ public final class ActivityThread {
                    handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
                            (IVoiceInteractor) ((SomeArgs) msg.obj).arg2);
                    break;
                case ATTACH_AGENT:
                    handleAttachAgent((String) msg.obj);
                case ATTACH_AGENT: {
                    Application app = getApplication();
                    handleAttachAgent((String) msg.obj, app != null ? app.mLoadedApk : null);
                    break;
                }
                case APPLICATION_INFO_CHANGED:
                    mUpdatingSystemConfig = true;
                    try {
@@ -3119,11 +3121,23 @@ public final class ActivityThread {
        }
    }

    static final void handleAttachAgent(String agent) {
    private static boolean attemptAttachAgent(String agent, ClassLoader classLoader) {
        try {
            VMDebug.attachAgent(agent);
            VMDebug.attachAgent(agent, classLoader);
            return true;
        } catch (IOException e) {
            Slog.e(TAG, "Attaching agent failed: " + agent);
            Slog.e(TAG, "Attaching agent with " + classLoader + " failed: " + agent);
            return false;
        }
    }

    static void handleAttachAgent(String agent, LoadedApk loadedApk) {
        ClassLoader classLoader = loadedApk != null ? loadedApk.getClassLoader() : null;
        if (attemptAttachAgent(agent, classLoader)) {
            return;
        }
        if (classLoader != null) {
            attemptAttachAgent(agent, null);
        }
    }

@@ -5441,12 +5455,16 @@ public final class ActivityThread {
        mCompatConfiguration = new Configuration(data.config);

        mProfiler = new Profiler();
        String agent = null;
        if (data.initProfilerInfo != null) {
            mProfiler.profileFile = data.initProfilerInfo.profileFile;
            mProfiler.profileFd = data.initProfilerInfo.profileFd;
            mProfiler.samplingInterval = data.initProfilerInfo.samplingInterval;
            mProfiler.autoStopProfiler = data.initProfilerInfo.autoStopProfiler;
            mProfiler.streamingOutput = data.initProfilerInfo.streamingOutput;
            if (data.initProfilerInfo.attachAgentDuringBind) {
                agent = data.initProfilerInfo.agent;
            }
        }

        // send up app name; do this *before* waiting for debugger
@@ -5496,6 +5514,10 @@ public final class ActivityThread {

        data.loadedApk = getLoadedApkNoCheck(data.appInfo, data.compatInfo);

        if (agent != null) {
            handleAttachAgent(agent, data.loadedApk);
        }

        /**
         * Switch this process to density compatibility mode if needed.
         */
+14 −1
Original line number Diff line number Diff line
@@ -54,14 +54,24 @@ public class ProfilerInfo implements Parcelable {
     */
    public final String agent;

    /**
     * Whether the {@link agent} should be attached early (before bind-application) or during
     * bind-application. Agents attached prior to binding cannot be loaded from the app's APK
     * directly and must be given as an absolute path (or available in the default LD_LIBRARY_PATH).
     * Agents attached during bind-application will miss early setup (e.g., resource initialization
     * and classloader generation), but are searched in the app's library search path.
     */
    public final boolean attachAgentDuringBind;

    public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop,
            boolean streaming, String agent) {
            boolean streaming, String agent, boolean attachAgentDuringBind) {
        profileFile = filename;
        profileFd = fd;
        samplingInterval = interval;
        autoStopProfiler = autoStop;
        streamingOutput = streaming;
        this.agent = agent;
        this.attachAgentDuringBind = attachAgentDuringBind;
    }

    public ProfilerInfo(ProfilerInfo in) {
@@ -71,6 +81,7 @@ public class ProfilerInfo implements Parcelable {
        autoStopProfiler = in.autoStopProfiler;
        streamingOutput = in.streamingOutput;
        agent = in.agent;
        attachAgentDuringBind = in.attachAgentDuringBind;
    }

    /**
@@ -109,6 +120,7 @@ public class ProfilerInfo implements Parcelable {
        out.writeInt(autoStopProfiler ? 1 : 0);
        out.writeInt(streamingOutput ? 1 : 0);
        out.writeString(agent);
        out.writeBoolean(attachAgentDuringBind);
    }

    public static final Parcelable.Creator<ProfilerInfo> CREATOR =
@@ -131,5 +143,6 @@ public class ProfilerInfo implements Parcelable {
        autoStopProfiler = in.readInt() != 0;
        streamingOutput = in.readInt() != 0;
        agent = in.readString();
        attachAgentDuringBind = in.readBoolean();
    }
}
+14 −7
Original line number Diff line number Diff line
@@ -7012,15 +7012,22 @@ public class ActivityManagerService extends IActivityManager.Stub
            }
            ProfilerInfo profilerInfo = null;
            String agent = null;
            String preBindAgent = null;
            if (mProfileApp != null && mProfileApp.equals(processName)) {
                mProfileProc = app;
                profilerInfo = (mProfilerInfo != null && mProfilerInfo.profileFile != null) ?
                        new ProfilerInfo(mProfilerInfo) : null;
                agent = mProfilerInfo != null ? mProfilerInfo.agent : null;
                if (mProfilerInfo != null) {
                    // Send a profiler info object to the app if either a file is given, or
                    // an agent should be loaded at bind-time.
                    boolean needsInfo = mProfilerInfo.profileFile != null
                            || mProfilerInfo.attachAgentDuringBind;
                    profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null;
                    if (!mProfilerInfo.attachAgentDuringBind) {
                        preBindAgent = mProfilerInfo.agent;
                    }
                }
            } else if (app.instr != null && app.instr.mProfileFile != null) {
                profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false,
                        null);
                        null, false);
            }
            boolean enableTrackAllocation = false;
@@ -7087,8 +7094,8 @@ public class ActivityManagerService extends IActivityManager.Stub
            // If we were asked to attach an agent on startup, do so now, before we're binding
            // application code.
            if (agent != null) {
                thread.attachAgent(agent);
            if (preBindAgent != null) {
                thread.attachAgent(preBindAgent);
            }
            checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
+18 −2
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
    private boolean mAutoStop;
    private boolean mStreaming;   // Streaming the profiling output to a file.
    private String mAgent;  // Agent to attach on startup.
    private boolean mAttachAgentDuringBind;  // Whether agent should be attached late.
    private int mDisplayId;
    private int mStackId;
    private int mTaskId;
@@ -295,7 +296,21 @@ final class ActivityManagerShellCommand extends ShellCommand {
                } else if (opt.equals("--streaming")) {
                    mStreaming = true;
                } else if (opt.equals("--attach-agent")) {
                    if (mAgent != null) {
                        cmd.getErrPrintWriter().println(
                                "Multiple --attach-agent(-bind) not supported");
                        return false;
                    }
                    mAgent = getNextArgRequired();
                    mAttachAgentDuringBind = false;
                } else if (opt.equals("--attach-agent-bind")) {
                    if (mAgent != null) {
                        cmd.getErrPrintWriter().println(
                                "Multiple --attach-agent(-bind) not supported");
                        return false;
                    }
                    mAgent = getNextArgRequired();
                    mAttachAgentDuringBind = true;
                } else if (opt.equals("-R")) {
                    mRepeat = Integer.parseInt(getNextArgRequired());
                } else if (opt.equals("-S")) {
@@ -381,7 +396,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
                    }
                }
                profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop,
                        mStreaming, mAgent);
                        mStreaming, mAgent, mAttachAgentDuringBind);
            }

            pw.println("Starting: " + intent);
@@ -755,7 +770,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
                return -1;
            }
            profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false, mStreaming,
                    null);
                    null, false);
        }

        try {
@@ -2679,6 +2694,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
            pw.println("          (use with --start-profiler)");
            pw.println("      -P <FILE>: like above, but profiling stops when app goes idle");
            pw.println("      --attach-agent <agent>: attach the given agent before binding");
            pw.println("      --attach-agent-bind <agent>: attach the given agent during binding");
            pw.println("      -R: repeat the activity launch <COUNT> times.  Prior to each repeat,");
            pw.println("          the top activity will be finished.");
            pw.println("      -S: force stop the target app before starting the activity");