diff options
6 files changed, 79 insertions, 1 deletions
| diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index cae4be69c0fe..2c4cf7449c34 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -974,6 +974,10 @@ public final class ActivityThread {              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 @@ -1408,6 +1412,7 @@ public final class ActivityThread {          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) { @@ -1464,6 +1469,7 @@ public final class ActivityThread {                      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); @@ -1718,6 +1724,8 @@ public final class ActivityThread {                  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; @@ -2987,6 +2995,14 @@ public final class ActivityThread {          }      } +    static final void handleAttachAgent(String agent) { +        try { +            VMDebug.attachAgent(agent); +        } catch (IOException e) { +            Slog.e(TAG, "Attaching agent failed: " + agent); +        } +    } +      private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();      /** diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 05d9d7e412f0..ad7f577f1e1d 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -502,6 +502,14 @@ public abstract class ApplicationThreadNative extends Binder              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(); @@ -1305,6 +1313,14 @@ class ApplicationThreadProxy implements IApplicationThread {          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 3fa88ae674a4..bfd97f8a2b27 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -123,6 +123,7 @@ public interface IApplicationThread extends IInterface {              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; @@ -225,4 +226,5 @@ public interface IApplicationThread extends IInterface {      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 fc804e592148..0b4c4c12d3df 100644 --- a/core/java/android/os/ShellCommand.java +++ b/core/java/android/os/ShellCommand.java @@ -274,7 +274,7 @@ public abstract class ShellCommand {      /**       * 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 81b13b7ba582..063591eff604 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -22273,4 +22273,29 @@ public final class ActivityManagerService extends ActivityManagerNative          // before the profile user is unlocked.          return rInfo != null && rInfo.activityInfo != null;      } + +    /** +     * 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 adf6d3670af3..2d0ccbd305e6 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 @@ class ActivityManagerShellCommand extends ShellCommand {                      return runLenientBackgroundCheck(pw);                  case "get-uid-state":                      return getUidState(pw); +                case "attach-agent": +                    return runAttachAgent(pw);                  default:                      return handleDefaultCommands(cmd);              } @@ -183,6 +185,21 @@ class ActivityManagerShellCommand extends ShellCommand {          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 @@ class ActivityManagerShellCommand extends ShellCommand {              pw.println("    Optionally controls lenient background check mode, returns current mode.");              pw.println("  get-uid-state <UID>");              pw.println("    Gets the process state of an app given its <UID>."); +            pw.println("  attach-agent <PROCESS> <FILE>"); +            pw.println("    Attach an agent to the specified <PROCESS>, which may be either a process name or a PID.");          }      }  } |