summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJing Ji <jji@google.com>2020-05-05 01:05:47 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-05-05 01:05:47 +0000
commite9fbacf6c5a6d88f96022b6d1c378de8c9000385 (patch)
treeae0b679b28322d3e233fe1ae40981b50e277bab4
parent316bc6ff66d9faa7f9d948255ef837cc3c652c7f (diff)
parent060d68630ddffbfa1ffc662d288f37c24a003769 (diff)
Merge "Support to pull aggregated procstats associations" into rvc-dev
-rw-r--r--cmds/statsd/src/atoms.proto21
-rw-r--r--core/java/com/android/internal/app/procstats/AssociationState.java2
-rw-r--r--core/java/com/android/internal/app/procstats/IProcessStats.aidl5
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessState.java7
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessStats.java139
-rw-r--r--core/proto/android/service/procstats.proto21
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java20
-rw-r--r--services/core/java/com/android/server/am/ProcessStatsService.java8
8 files changed, 218 insertions, 5 deletions
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 3017ec024151..34c178b4cbce 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5699,7 +5699,7 @@ message ProcessStatsStateProto {
optional AggStats rss = 8;
}
-// Next Tag: 7
+// Next Tag: 8
message ProcessStatsProto {
// Name of process.
optional string process = 1;
@@ -5726,6 +5726,25 @@ message ProcessStatsProto {
// Total time process has been running... screen_state, memory_state, and process_state
// will not be set.
optional ProcessStatsStateProto total_running_state = 6;
+
+ // Association data for this process in this state;
+ // each entry here is one association.
+ repeated ProcessStatsAssociationProto assocs = 7;
+}
+
+// Next Tag: 5
+message ProcessStatsAssociationProto {
+ // Procss Name of the associated process (client process of service binding)
+ optional string assoc_process_name = 1;
+
+ // Package Name of the associated package (client package of service binding)
+ optional string assoc_package_name = 2;
+
+ // Total count of the times this association (service binding) appeared.
+ optional int32 total_count = 3;
+
+ // Uptime total duration in seconds this association (service binding) was around.
+ optional int32 total_duration_secs = 4;
}
message PackageServiceOperationStatsProto {
diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java
index dea35669b591..8fef8378f33c 100644
--- a/core/java/com/android/internal/app/procstats/AssociationState.java
+++ b/core/java/com/android/internal/app/procstats/AssociationState.java
@@ -288,7 +288,7 @@ public final class AssociationState {
/**
* All known sources for this target component... uid -> process name -> source state.
*/
- private final ArrayMap<SourceKey, SourceState> mSources = new ArrayMap<>();
+ final ArrayMap<SourceKey, SourceState> mSources = new ArrayMap<>();
private static final SourceKey sTmpSourceKey = new SourceKey(0, null, null);
diff --git a/core/java/com/android/internal/app/procstats/IProcessStats.aidl b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
index 7a6301f6f180..a2eca3aee13d 100644
--- a/core/java/com/android/internal/app/procstats/IProcessStats.aidl
+++ b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
@@ -45,4 +45,9 @@ interface IProcessStats {
*/
long getCommittedStatsMerged(long highWaterMarkMs, int section, boolean doAggregate,
out List<ParcelFileDescriptor> committedStats, out ProcessStats mergedStats);
+
+ /**
+ * @return The threshold to decide if a given association should be dumped into metrics.
+ */
+ long getMinAssociationDumpDuration();
}
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index fe4138584fa7..b8142607ebd7 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -50,6 +50,7 @@ import android.os.UserHandle;
import android.service.procstats.ProcessStatsProto;
import android.service.procstats.ProcessStatsStateProto;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
import android.util.LongSparseArray;
@@ -59,6 +60,7 @@ import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
+import com.android.internal.app.ProcessMap;
import com.android.internal.app.procstats.ProcessStats.PackageState;
import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
@@ -1420,7 +1422,8 @@ public final class ProcessState {
/** Similar to {@code #dumpDebug}, but with a reduced/aggregated subset of states. */
public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId,
- String procName, int uid, long now) {
+ String procName, int uid, long now,
+ final ProcessMap<ArraySet<PackageState>> procToPkgMap) {
// Group proc stats by aggregated type (only screen state + process state)
SparseLongArray durationByState = new SparseLongArray();
boolean didCurState = false;
@@ -1524,6 +1527,8 @@ public final class ProcessState {
proto.end(stateToken);
}
+ mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS,
+ now, this, procToPkgMap);
proto.end(token);
}
}
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 80f6272794d1..928ba35595d3 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -20,12 +20,16 @@ import android.content.ComponentName;
import android.os.Debug;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.service.procstats.ProcessStatsAssociationProto;
import android.service.procstats.ProcessStatsAvailablePagesProto;
import android.service.procstats.ProcessStatsPackageProto;
import android.service.procstats.ProcessStatsSectionProto;
+import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -38,6 +42,8 @@ import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import com.android.internal.app.ProcessMap;
+import com.android.internal.app.procstats.AssociationState.SourceKey;
+import com.android.internal.app.procstats.AssociationState.SourceState;
import dalvik.system.VMRuntime;
@@ -2229,6 +2235,8 @@ public final class ProcessStats implements Parcelable {
public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto) {
dumpProtoPreamble(proto);
final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ final ProcessMap<ArraySet<PackageState>> procToPkgMap =
+ collectProcessPackageMaps(null, false);
for (int ip = 0; ip < procMap.size(); ip++) {
final String procName = procMap.keyAt(ip);
final SparseArray<ProcessState> uids = procMap.valueAt(ip);
@@ -2237,7 +2245,7 @@ public final class ProcessStats implements Parcelable {
final ProcessState procState = uids.valueAt(iu);
procState.dumpAggregatedProtoForStatsd(proto,
ProcessStatsSectionProto.PROCESS_STATS,
- procName, uid, mTimePeriodEndRealtime);
+ procName, uid, mTimePeriodEndRealtime, procToPkgMap);
}
}
}
@@ -2268,6 +2276,135 @@ public final class ProcessStats implements Parcelable {
}
}
+ /**
+ * Walk through the known processes and build up the process -> packages map if necessary.
+ */
+ public ProcessMap<ArraySet<PackageState>> collectProcessPackageMaps(
+ String reqPackage, boolean activeOnly) {
+ final ProcessMap<ArraySet<PackageState>> map = new ProcessMap<>();
+
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
+ for (int ip = pkgMap.size() - 1; ip >= 0; ip--) {
+ final String pkgName = pkgMap.keyAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> procs = pkgMap.valueAt(ip);
+ for (int iu = procs.size() - 1; iu >= 0; iu--) {
+ final LongSparseArray<PackageState> vpkgs = procs.valueAt(iu);
+ for (int iv = vpkgs.size() - 1; iv >= 0; iv--) {
+ final PackageState state = vpkgs.valueAt(iv);
+ final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+ for (int iproc = state.mProcesses.size() - 1; iproc >= 0; iproc--) {
+ final ProcessState proc = state.mProcesses.valueAt(iproc);
+ if (!pkgMatch && !reqPackage.equals(proc.getName())) {
+ continue;
+ }
+ if (activeOnly && !proc.isInUse()) {
+ continue;
+ }
+
+ final String name = proc.getName();
+ final int uid = proc.getUid();
+ ArraySet<PackageState> pkgStates = map.get(name, uid);
+ if (pkgStates == null) {
+ pkgStates = new ArraySet<>();
+ map.put(name, uid, pkgStates);
+ }
+ pkgStates.add(state);
+ }
+ }
+ }
+ }
+ return map;
+ }
+
+ /**
+ * Dump the association states related to given process into statsd.
+ *
+ * <p> Note: Only dump the single-package process state, or the common process state of
+ * multi-package process; while the per-package process state of a multi-package process
+ * should not be dumped into the statsd due to its incompletion.</p>
+ *
+ * @param proto The proto output stream
+ * @param fieldId The proto output field ID
+ * @param now The timestamp when the dump was initiated.
+ * @param procState The target process where its association states should be dumped.
+ * @param proc2Pkg The map between process to packages running within it.
+ */
+ public void dumpFilteredAssociationStatesProtoForProc(ProtoOutputStream proto,
+ long fieldId, long now, ProcessState procState,
+ final ProcessMap<ArraySet<PackageState>> proc2Pkg) {
+ if (procState.isMultiPackage() && procState.getCommonProcess() != procState) {
+ // It's a per-package process state, don't bother to write into statsd
+ return;
+ }
+ ArrayMap<SourceKey, long[]> assocVals = new ArrayMap<>();
+ final String procName = procState.getName();
+ final int procUid = procState.getUid();
+ final long procVersion = procState.getVersion();
+ final ArraySet<PackageState> packages = proc2Pkg.get(procName, procUid);
+ if (packages == null || packages.isEmpty()) {
+ // Shouldn't happen
+ return;
+ }
+ for (int i = packages.size() - 1; i >= 0; i--) {
+ final PackageState pkgState = packages.valueAt(i);
+ final ArrayMap<String, AssociationState> associations = pkgState.mAssociations;
+ for (int j = associations.size() - 1; j >= 0; j--) {
+ final AssociationState assoc = associations.valueAt(j);
+ // Make sure this association is really about this process
+ if (!TextUtils.equals(assoc.getProcessName(), procName)) {
+ continue;
+ }
+ final ArrayMap<SourceKey, SourceState> sources = assoc.mSources;
+ for (int k = sources.size() - 1; k >= 0; k--) {
+ final SourceKey key = sources.keyAt(k);
+ final SourceState state = sources.valueAt(k);
+ long[] vals = assocVals.get(key);
+ if (vals == null) {
+ vals = new long[2];
+ assocVals.put(key, vals);
+ }
+ vals[0] += state.mDuration;
+ vals[1] += state.mCount;
+ if (state.mNesting > 0) {
+ vals[0] += now - state.mStartUptime;
+ }
+ }
+ }
+ }
+ final IProcessStats procStatsService = IProcessStats.Stub.asInterface(
+ ServiceManager.getService(SERVICE_NAME));
+ if (procStatsService != null) {
+ try {
+ final long minimum = procStatsService.getMinAssociationDumpDuration();
+ if (minimum > 0) {
+ // Now filter out unnecessary ones.
+ for (int i = assocVals.size() - 1; i >= 0; i--) {
+ final long[] vals = assocVals.valueAt(i);
+ if (vals[0] < minimum) {
+ assocVals.removeAt(i);
+ }
+ }
+ }
+ } catch (RemoteException e) {
+ // ignore.
+ }
+ }
+ if (!assocVals.isEmpty()) {
+ for (int i = assocVals.size() - 1; i >= 0; i--) {
+ final SourceKey key = assocVals.keyAt(i);
+ final long[] vals = assocVals.valueAt(i);
+ final long token = proto.start(fieldId);
+ proto.write(ProcessStatsAssociationProto.ASSOC_PROCESS_NAME, key.mProcess);
+ proto.write(ProcessStatsAssociationProto.ASSOC_PACKAGE_NAME, key.mPackage);
+ proto.write(ProcessStatsAssociationProto.TOTAL_COUNT, (int) vals[1]);
+ proto.write(ProcessStatsAssociationProto.TOTAL_DURATION_SECS,
+ (int) (vals[0] / 1000));
+ proto.end(token);
+ }
+ }
+ }
+
final public static class ProcessStateHolder {
public final long appVersion;
public ProcessState state;
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index a6dc937566c2..dd830a85edc9 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -142,7 +142,7 @@ message ProcessStatsStateProto {
optional android.util.AggStats rss = 8;
}
-// Next Tag: 7
+// Next Tag: 8
message ProcessStatsProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -173,6 +173,25 @@ message ProcessStatsProto {
// Total time process has been running... screen_state, memory_state, and process_state
// will not be set.
optional ProcessStatsStateProto total_running_state = 6;
+
+ // Association data for this process in this state;
+ // each entry here is one association.
+ repeated ProcessStatsAssociationProto assocs = 7;
+}
+
+// Next Tag: 5
+message ProcessStatsAssociationProto {
+ // Procss Name of the associated process/package
+ optional string assoc_process_name = 1;
+
+ // Package Name of the associated process/package
+ optional string assoc_package_name = 2;
+
+ // Total count of the times this association appeared.
+ optional int32 total_count = 3;
+
+ // Uptime total duration in seconds this association was around.
+ optional int32 total_duration_secs = 4;
}
// Next Tag: 4
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 6b917bc2249d..4ff421e6cdf5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -367,6 +367,15 @@ final class ActivityManagerConstants extends ContentObserver {
private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
+ /**
+ * The threshold to decide if a given association should be dumped into metrics.
+ */
+ private static final long DEFAULT_MIN_ASSOC_LOG_DURATION = 5 * 60 * 1000; // 5 mins
+
+ private static final String KEY_MIN_ASSOC_LOG_DURATION = "min_assoc_log_duration";
+
+ public static long MIN_ASSOC_LOG_DURATION = DEFAULT_MIN_ASSOC_LOG_DURATION;
+
private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
new OnPropertiesChangedListener() {
@Override
@@ -395,6 +404,9 @@ final class ActivityManagerConstants extends ContentObserver {
case KEY_FORCE_BACKGROUND_CHECK_ON_RESTRICTED_APPS:
updateForceRestrictedBackgroundCheck();
break;
+ case KEY_MIN_ASSOC_LOG_DURATION:
+ updateMinAssocLogDuration();
+ break;
default:
break;
}
@@ -659,6 +671,12 @@ final class ActivityManagerConstants extends ContentObserver {
CUR_TRIM_CACHED_PROCESSES = (MAX_CACHED_PROCESSES-rawMaxEmptyProcesses)/3;
}
+ private void updateMinAssocLogDuration() {
+ MIN_ASSOC_LOG_DURATION = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_MIN_ASSOC_LOG_DURATION,
+ /* defaultValue */ DEFAULT_MIN_ASSOC_LOG_DURATION);
+ }
+
void dump(PrintWriter pw) {
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":");
@@ -729,6 +747,8 @@ final class ActivityManagerConstants extends ContentObserver {
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PROC_STATES.toArray()));
pw.print(" "); pw.print(KEY_IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES); pw.print("=");
pw.println(Arrays.toString(IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.toArray()));
+ pw.print(" "); pw.print(KEY_MIN_ASSOC_LOG_DURATION); pw.print("=");
+ pw.println(MIN_ASSOC_LOG_DURATION);
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 6d4a9f42ccd9..a0349493edbc 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -617,6 +617,14 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return newHighWaterMark;
}
+ /**
+ * @return The threshold to decide if a given association should be dumped into metrics.
+ */
+ @Override
+ public long getMinAssociationDumpDuration() {
+ return mAm.mConstants.MIN_ASSOC_LOG_DURATION;
+ }
+
private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section)
throws IOException {
final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();