Loading core/java/android/app/IActivityManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ interface IActivityManager { void publishService(in IBinder token, in Intent intent, in IBinder service); void activityResumed(in IBinder token); void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent); void setAgentApp(in String packageName, @nullable String agent); void setAlwaysFinish(boolean enabled); boolean startInstrumentation(in ComponentName className, in String profileFile, int flags, in Bundle arguments, in IInstrumentationWatcher watcher, Loading core/java/android/app/ProfilerInfo.java +9 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,15 @@ public class ProfilerInfo implements Parcelable { attachAgentDuringBind = in.attachAgentDuringBind; } /** * Return a new ProfilerInfo instance, with fields populated from this object, * and {@link agent} and {@link attachAgentDuringBind} as given. */ public ProfilerInfo setAgent(String agent, boolean attachAgentDuringBind) { return new ProfilerInfo(this.profileFile, this.profileFd, this.samplingInterval, this.autoStopProfiler, this.streamingOutput, agent, attachAgentDuringBind); } /** * Close profileFd, if it is open. The field will be null after a call to this function. */ Loading services/core/java/com/android/server/am/ActivityManagerService.java +87 −19 Original line number Diff line number Diff line Loading @@ -1493,6 +1493,14 @@ public class ActivityManagerService extends IActivityManager.Stub String mProfileApp = null; ProcessRecord mProfileProc = null; ProfilerInfo mProfilerInfo = null; /** * Stores a map of process name -> agent string. When a process is started and mAgentAppMap * is not null, this map is checked and the mapped agent installed during bind-time. Note: * A non-null agent in mProfileInfo overrides this. */ private @Nullable Map<String, String> mAppAgentMap = null; int mProfileType = 0; final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>(); String mMemWatchDumpProcName; Loading Loading @@ -7017,25 +7025,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } ProfilerInfo profilerInfo = null; String preBindAgent = null; if (mProfileApp != null && mProfileApp.equals(processName)) { mProfileProc = app; 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, false); } boolean enableTrackAllocation = false; if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) { enableTrackAllocation = true; Loading @@ -7060,6 +7049,39 @@ public class ActivityManagerService extends IActivityManager.Stub ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info; app.compat = compatibilityInfoForPackageLocked(appInfo); ProfilerInfo profilerInfo = null; String preBindAgent = null; if (mProfileApp != null && mProfileApp.equals(processName)) { mProfileProc = app; 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.agent != null) { preBindAgent = mProfilerInfo.agent; } } } else if (app.instr != null && app.instr.mProfileFile != null) { profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false, null, false); } if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) { // We need to do a debuggable check here. See setAgentApp for why the check is // postponed to here. if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { String agent = mAppAgentMap.get(processName); // Do not overwrite already requested agent. if (profilerInfo == null) { profilerInfo = new ProfilerInfo(null, null, 0, false, false, mAppAgentMap.get(processName), true); } else if (profilerInfo.agent == null) { profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true); } } } if (profilerInfo != null && profilerInfo.profileFd != null) { profilerInfo.profileFd = profilerInfo.profileFd.dup(); } Loading Loading @@ -12793,6 +12815,52 @@ public class ActivityManagerService extends IActivityManager.Stub } } /** * Set or remove an agent to be run whenever an app with the given process name starts. * * This method will not check whether the given process name matches a debuggable app. That * would require scanning all current packages, and a rescan when new packages are installed * or updated. * * Instead, do the check when an application is started and matched to a stored agent. * * @param packageName the process name of the app. * @param agent the agent string to be used, or null to remove any previously set agent. */ @Override public void setAgentApp(@NonNull String packageName, @Nullable String agent) { synchronized (this) { // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to // its own permission. if (checkCallingPermission( android.Manifest.permission.SET_ACTIVITY_WATCHER) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException( "Requires permission " + android.Manifest.permission.SET_ACTIVITY_WATCHER); } if (agent == null) { if (mAppAgentMap != null) { mAppAgentMap.remove(packageName); if (mAppAgentMap.isEmpty()) { mAppAgentMap = null; } } } else { if (mAppAgentMap == null) { mAppAgentMap = new HashMap<>(); } if (mAppAgentMap.size() >= 100) { // Limit the size of the map, to avoid OOMEs. Slog.e(TAG, "App agent map has too many entries, cannot add " + packageName + "/" + agent); return; } mAppAgentMap.put(packageName, agent); } } } void setTrackAllocationApp(ApplicationInfo app, String processName) { synchronized (this) { boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); services/core/java/com/android/server/am/ActivityManagerShellCommand.java +9 −0 Original line number Diff line number Diff line Loading @@ -164,6 +164,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runDumpHeap(pw); case "set-debug-app": return runSetDebugApp(pw); case "set-agent-app": return runSetAgentApp(pw); case "clear-debug-app": return runClearDebugApp(pw); case "set-watch-heap": Loading Loading @@ -862,6 +864,13 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } int runSetAgentApp(PrintWriter pw) throws RemoteException { String pkg = getNextArgRequired(); String agent = getNextArg(); mInterface.setAgentApp(pkg, agent); return 0; } int runClearDebugApp(PrintWriter pw) throws RemoteException { mInterface.setDebugApp(null, false, true); return 0; Loading Loading
core/java/android/app/IActivityManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ interface IActivityManager { void publishService(in IBinder token, in Intent intent, in IBinder service); void activityResumed(in IBinder token); void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent); void setAgentApp(in String packageName, @nullable String agent); void setAlwaysFinish(boolean enabled); boolean startInstrumentation(in ComponentName className, in String profileFile, int flags, in Bundle arguments, in IInstrumentationWatcher watcher, Loading
core/java/android/app/ProfilerInfo.java +9 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,15 @@ public class ProfilerInfo implements Parcelable { attachAgentDuringBind = in.attachAgentDuringBind; } /** * Return a new ProfilerInfo instance, with fields populated from this object, * and {@link agent} and {@link attachAgentDuringBind} as given. */ public ProfilerInfo setAgent(String agent, boolean attachAgentDuringBind) { return new ProfilerInfo(this.profileFile, this.profileFd, this.samplingInterval, this.autoStopProfiler, this.streamingOutput, agent, attachAgentDuringBind); } /** * Close profileFd, if it is open. The field will be null after a call to this function. */ Loading
services/core/java/com/android/server/am/ActivityManagerService.java +87 −19 Original line number Diff line number Diff line Loading @@ -1493,6 +1493,14 @@ public class ActivityManagerService extends IActivityManager.Stub String mProfileApp = null; ProcessRecord mProfileProc = null; ProfilerInfo mProfilerInfo = null; /** * Stores a map of process name -> agent string. When a process is started and mAgentAppMap * is not null, this map is checked and the mapped agent installed during bind-time. Note: * A non-null agent in mProfileInfo overrides this. */ private @Nullable Map<String, String> mAppAgentMap = null; int mProfileType = 0; final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>(); String mMemWatchDumpProcName; Loading Loading @@ -7017,25 +7025,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } ProfilerInfo profilerInfo = null; String preBindAgent = null; if (mProfileApp != null && mProfileApp.equals(processName)) { mProfileProc = app; 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, false); } boolean enableTrackAllocation = false; if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) { enableTrackAllocation = true; Loading @@ -7060,6 +7049,39 @@ public class ActivityManagerService extends IActivityManager.Stub ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info; app.compat = compatibilityInfoForPackageLocked(appInfo); ProfilerInfo profilerInfo = null; String preBindAgent = null; if (mProfileApp != null && mProfileApp.equals(processName)) { mProfileProc = app; 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.agent != null) { preBindAgent = mProfilerInfo.agent; } } } else if (app.instr != null && app.instr.mProfileFile != null) { profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false, null, false); } if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) { // We need to do a debuggable check here. See setAgentApp for why the check is // postponed to here. if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { String agent = mAppAgentMap.get(processName); // Do not overwrite already requested agent. if (profilerInfo == null) { profilerInfo = new ProfilerInfo(null, null, 0, false, false, mAppAgentMap.get(processName), true); } else if (profilerInfo.agent == null) { profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true); } } } if (profilerInfo != null && profilerInfo.profileFd != null) { profilerInfo.profileFd = profilerInfo.profileFd.dup(); } Loading Loading @@ -12793,6 +12815,52 @@ public class ActivityManagerService extends IActivityManager.Stub } } /** * Set or remove an agent to be run whenever an app with the given process name starts. * * This method will not check whether the given process name matches a debuggable app. That * would require scanning all current packages, and a rescan when new packages are installed * or updated. * * Instead, do the check when an application is started and matched to a stored agent. * * @param packageName the process name of the app. * @param agent the agent string to be used, or null to remove any previously set agent. */ @Override public void setAgentApp(@NonNull String packageName, @Nullable String agent) { synchronized (this) { // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to // its own permission. if (checkCallingPermission( android.Manifest.permission.SET_ACTIVITY_WATCHER) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException( "Requires permission " + android.Manifest.permission.SET_ACTIVITY_WATCHER); } if (agent == null) { if (mAppAgentMap != null) { mAppAgentMap.remove(packageName); if (mAppAgentMap.isEmpty()) { mAppAgentMap = null; } } } else { if (mAppAgentMap == null) { mAppAgentMap = new HashMap<>(); } if (mAppAgentMap.size() >= 100) { // Limit the size of the map, to avoid OOMEs. Slog.e(TAG, "App agent map has too many entries, cannot add " + packageName + "/" + agent); return; } mAppAgentMap.put(packageName, agent); } } } void setTrackAllocationApp(ApplicationInfo app, String processName) { synchronized (this) { boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
services/core/java/com/android/server/am/ActivityManagerShellCommand.java +9 −0 Original line number Diff line number Diff line Loading @@ -164,6 +164,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runDumpHeap(pw); case "set-debug-app": return runSetDebugApp(pw); case "set-agent-app": return runSetAgentApp(pw); case "clear-debug-app": return runClearDebugApp(pw); case "set-watch-heap": Loading Loading @@ -862,6 +864,13 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } int runSetAgentApp(PrintWriter pw) throws RemoteException { String pkg = getNextArgRequired(); String agent = getNextArg(); mInterface.setAgentApp(pkg, agent); return 0; } int runClearDebugApp(PrintWriter pw) throws RemoteException { mInterface.setDebugApp(null, false, true); return 0; Loading