diff options
| author | 2018-01-05 13:55:15 -0800 | |
|---|---|---|
| committer | 2018-01-15 13:04:25 -0800 | |
| commit | ab8a63be6afc428a752828f9ea6423047cd27e42 (patch) | |
| tree | 294e16224f85e4471fb9d1b74992b085bd662c48 | |
| parent | 9cb0b520114c1a166f4972b53cb2bfac7d1a1b78 (diff) | |
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
4 files changed, 73 insertions, 15 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 7bda37e09f41..2ecd3120345d 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -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. */ diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java index fad4798e3a3e..044b78003bd7 100644 --- a/core/java/android/app/ProfilerInfo.java +++ b/core/java/android/app/ProfilerInfo.java @@ -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(); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6cdf0712c7c1..002381a5a3f0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -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"); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 8488e526eba9..a7ace21607b5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -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"); |