From 1ab879be90a0d58219fca206e556349709fdfda0 Mon Sep 17 00:00:00 2001 From: Leonard Mosescu Date: Thu, 6 Oct 2016 17:32:05 -0700 Subject: [PATCH] Adding "attach-agent" to ActivityManagerShellCommand This new command is used to attach runtime agents to a running application: attach-agent Attach an agent to the specified , which may be either a process name or a PID. Test: m test-art-host, manual testing: . invalid syntax, missing arguments . invalid syntax, extra arguments . invalid numeric PID . invalid process name . valid process, not debuggable . valid process, missing agent . valid process, valid agent Bug: 31682382 Change-Id: Ife88dbf23991dde7945d9208e54cd014bb7ecdc6 Merged-In: Ife88dbf23991dde7945d9208e54cd014bb7ecdc6 --- core/java/android/app/ActivityThread.java | 16 ++++++++++++ .../android/app/ApplicationThreadNative.java | 16 ++++++++++++ core/java/android/app/IApplicationThread.java | 2 ++ core/java/android/os/ShellCommand.java | 2 +- .../server/am/ActivityManagerService.java | 25 +++++++++++++++++++ .../am/ActivityManagerShellCommand.java | 19 ++++++++++++++ 6 files changed, 79 insertions(+), 1 deletion(-) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 83dab164aef76..c1b37e6d26233 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -965,6 +965,10 @@ public void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd) { sendMessage(H.DUMP_HEAP, dhd, managed ? 1 : 0, 0, true /*async*/); } + public void attachAgent(String agent) { + sendMessage(H.ATTACH_AGENT, agent); + } + public void setSchedulingGroup(int group) { // Note: do this immediately, since going into the foreground // should happen regardless of what pending work we have to do @@ -1388,6 +1392,7 @@ private class H extends Handler { public static final int MULTI_WINDOW_MODE_CHANGED = 152; public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153; public static final int LOCAL_VOICE_INTERACTION_STARTED = 154; + public static final int ATTACH_AGENT = 155; String codeToString(int code) { if (DEBUG_MESSAGES) { @@ -1444,6 +1449,7 @@ String codeToString(int code) { case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED"; case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED"; case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED"; + case ATTACH_AGENT: return "ATTACH_AGENT"; } } return Integer.toString(code); @@ -1696,6 +1702,8 @@ public void handleMessage(Message msg) { case LOCAL_VOICE_INTERACTION_STARTED: handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1, (IVoiceInteractor) ((SomeArgs) msg.obj).arg2); + case ATTACH_AGENT: + handleAttachAgent((String) msg.obj); break; } Object obj = msg.obj; @@ -2955,6 +2963,14 @@ private void handleLocalVoiceInteractionStarted(IBinder token, IVoiceInteractor } } + static final void handleAttachAgent(String agent) { + try { + VMDebug.attachAgent(agent); + } catch (IOException e) { + Slog.e(TAG, "Attaching agent failed: " + agent); + } + } + private static final ThreadLocal sCurrentBroadcastIntent = new ThreadLocal(); /** diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index d6da3f44f4a00..a8313d1524225 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -501,6 +501,14 @@ public boolean onTransact(int code, Parcel data, Parcel reply, int flags) return true; } + case ATTACH_AGENT_TRANSACTION: + { + data.enforceInterface(IApplicationThread.descriptor); + String agent = data.readString(); + attachAgent(agent); + return true; + } + case DUMP_ACTIVITY_TRANSACTION: { data.enforceInterface(IApplicationThread.descriptor); ParcelFileDescriptor fd = data.readFileDescriptor(); @@ -1303,6 +1311,14 @@ public void dumpActivity(FileDescriptor fd, IBinder token, String prefix, String data.recycle(); } + public void attachAgent(String agent) throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + data.writeString(agent); + mRemote.transact(ATTACH_AGENT_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); + data.recycle(); + } + public void setCoreSettings(Bundle coreSettings) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 559f69fc2aec1..5b13164ddb4a2 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -122,6 +122,7 @@ void profilerControl(boolean start, ProfilerInfo profilerInfo, int profileType) throws RemoteException; void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd) throws RemoteException; + void attachAgent(String path) throws RemoteException; void setSchedulingGroup(int group) throws RemoteException; // the package has been removed, clean up internal references static final int PACKAGE_REMOVED = 0; @@ -224,4 +225,5 @@ void scheduleOnNewActivityOptions(IBinder token, ActivityOptions options) int SCHEDULE_MULTI_WINDOW_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+58; int SCHEDULE_PICTURE_IN_PICTURE_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+59; int SCHEDULE_LOCAL_VOICE_INTERACTION_STARTED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+60; + int ATTACH_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+61; } diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java index fc804e5921483..0b4c4c12d3df7 100644 --- a/core/java/android/os/ShellCommand.java +++ b/core/java/android/os/ShellCommand.java @@ -274,7 +274,7 @@ public int handleDefaultCommands(String cmd) { /** * Implement parsing and execution of a command. If it isn't a command you understand, * call {@link #handleDefaultCommands(String)} and return its result as a last resort. - * User {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()} + * Use {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()} * to process additional command line arguments. Command output can be written to * {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}. * diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c985a5853b5d8..fdde150136633 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -21831,4 +21831,29 @@ public void killPackageDependents(String packageName, int userId) { Binder.restoreCallingIdentity(callingId); } } + + /** + * Attach an agent to the specified process (proces name or PID) + */ + public void attachAgent(String process, String path) { + try { + synchronized (this) { + ProcessRecord proc = findProcessLocked(process, UserHandle.USER_SYSTEM, "attachAgent"); + if (proc == null || proc.thread == null) { + throw new IllegalArgumentException("Unknown process: " + process); + } + + boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); + if (!isDebuggable) { + if ((proc.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) { + throw new SecurityException("Process not debuggable: " + proc); + } + } + + proc.thread.attachAgent(path); + } + } catch (RemoteException e) { + throw new IllegalStateException("Process disappeared"); + } + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index adf6d3670af3d..2d0ccbd305e6b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -66,6 +66,8 @@ public int onCommand(String cmd) { return runLenientBackgroundCheck(pw); case "get-uid-state": return getUidState(pw); + case "attach-agent": + return runAttachAgent(pw); default: return handleDefaultCommands(cmd); } @@ -183,6 +185,21 @@ int getUidState(PrintWriter pw) throws RemoteException { return 0; } + int runAttachAgent(PrintWriter pw) { + // TODO: revisit the permissions required for attaching agents + mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER, + "attach-agent"); + String process = getNextArgRequired(); + String agent = getNextArgRequired(); + String opt; + if ((opt = getNextArg()) != null) { + pw.println("Error: Unknown option: " + opt); + return -1; + } + mInternal.attachAgent(process, agent); + return 0; + } + @Override public void onHelp() { PrintWriter pw = getOutPrintWriter(); @@ -241,6 +258,8 @@ static void dumpHelp(PrintWriter pw, boolean dumping) { pw.println(" Optionally controls lenient background check mode, returns current mode."); pw.println(" get-uid-state "); pw.println(" Gets the process state of an app given its ."); + pw.println(" attach-agent "); + pw.println(" Attach an agent to the specified , which may be either a process name or a PID."); } } }