Merge "ActivityManager: Add support for agents on startup"

This commit is contained in:
Treehugger Robot
2018-01-25 18:08:07 +00:00
committed by Gerrit Code Review
4 changed files with 106 additions and 19 deletions

View File

@@ -137,6 +137,7 @@ interface IActivityManager {
void publishService(in IBinder token, in Intent intent, in IBinder service); void publishService(in IBinder token, in Intent intent, in IBinder service);
void activityResumed(in IBinder token); void activityResumed(in IBinder token);
void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent); void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent);
void setAgentApp(in String packageName, @nullable String agent);
void setAlwaysFinish(boolean enabled); void setAlwaysFinish(boolean enabled);
boolean startInstrumentation(in ComponentName className, in String profileFile, boolean startInstrumentation(in ComponentName className, in String profileFile,
int flags, in Bundle arguments, in IInstrumentationWatcher watcher, int flags, in Bundle arguments, in IInstrumentationWatcher watcher,

View File

@@ -84,6 +84,15 @@ public class ProfilerInfo implements Parcelable {
attachAgentDuringBind = in.attachAgentDuringBind; 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. * Close profileFd, if it is open. The field will be null after a call to this function.
*/ */

View File

@@ -1493,6 +1493,14 @@ public class ActivityManagerService extends IActivityManager.Stub
String mProfileApp = null; String mProfileApp = null;
ProcessRecord mProfileProc = null; ProcessRecord mProfileProc = null;
ProfilerInfo mProfilerInfo = 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; int mProfileType = 0;
final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>(); final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();
String mMemWatchDumpProcName; String mMemWatchDumpProcName;
@@ -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; boolean enableTrackAllocation = false;
if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) { if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {
enableTrackAllocation = true; enableTrackAllocation = true;
@@ -7060,6 +7049,39 @@ public class ActivityManagerService extends IActivityManager.Stub
ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info; ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo); 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) { if (profilerInfo != null && profilerInfo.profileFd != null) {
profilerInfo.profileFd = profilerInfo.profileFd.dup(); profilerInfo.profileFd = profilerInfo.profileFd.dup();
} }
@@ -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) { void setTrackAllocationApp(ApplicationInfo app, String processName) {
synchronized (this) { synchronized (this) {
boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));

View File

@@ -164,6 +164,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
return runDumpHeap(pw); return runDumpHeap(pw);
case "set-debug-app": case "set-debug-app":
return runSetDebugApp(pw); return runSetDebugApp(pw);
case "set-agent-app":
return runSetAgentApp(pw);
case "clear-debug-app": case "clear-debug-app":
return runClearDebugApp(pw); return runClearDebugApp(pw);
case "set-watch-heap": case "set-watch-heap":
@@ -862,6 +864,13 @@ final class ActivityManagerShellCommand extends ShellCommand {
return 0; 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 { int runClearDebugApp(PrintWriter pw) throws RemoteException {
mInterface.setDebugApp(null, false, true); mInterface.setDebugApp(null, false, true);
return 0; return 0;