diff options
author | Jing Ji <jji@google.com> | 2020-05-05 01:05:47 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-05-05 01:05:47 +0000 |
commit | e9fbacf6c5a6d88f96022b6d1c378de8c9000385 (patch) | |
tree | ae0b679b28322d3e233fe1ae40981b50e277bab4 | |
parent | 316bc6ff66d9faa7f9d948255ef837cc3c652c7f (diff) | |
parent | 060d68630ddffbfa1ffc662d288f37c24a003769 (diff) |
Merge "Support to pull aggregated procstats associations" into rvc-dev
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(); |