Merge "Support aggregation over association sources per process" into sc-dev
This commit is contained in:
@@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
package com.android.internal.app.procstats;
|
package com.android.internal.app.procstats;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.service.procstats.PackageAssociationProcessStatsProto;
|
import android.service.procstats.PackageAssociationProcessStatsProto;
|
||||||
@@ -54,7 +56,14 @@ public final class AssociationState {
|
|||||||
private int mTotalActiveCount;
|
private int mTotalActiveCount;
|
||||||
private long mTotalActiveDuration;
|
private long mTotalActiveDuration;
|
||||||
|
|
||||||
public final class SourceState {
|
/**
|
||||||
|
* The state of the source process of an association.
|
||||||
|
*/
|
||||||
|
public static final class SourceState implements Parcelable {
|
||||||
|
private @NonNull final ProcessStats mProcessStats;
|
||||||
|
private @Nullable final AssociationState mAssociationState;
|
||||||
|
private @Nullable final ProcessState mTargetProcess;
|
||||||
|
private @Nullable SourceState mCommonSourceState;
|
||||||
final SourceKey mKey;
|
final SourceKey mKey;
|
||||||
int mProcStateSeq = -1;
|
int mProcStateSeq = -1;
|
||||||
int mProcState = ProcessStats.STATE_NOTHING;
|
int mProcState = ProcessStats.STATE_NOTHING;
|
||||||
@@ -64,18 +73,24 @@ public final class AssociationState {
|
|||||||
long mStartUptime;
|
long mStartUptime;
|
||||||
long mDuration;
|
long mDuration;
|
||||||
long mTrackingUptime;
|
long mTrackingUptime;
|
||||||
|
int mActiveNesting;
|
||||||
int mActiveCount;
|
int mActiveCount;
|
||||||
int mActiveProcState = ProcessStats.STATE_NOTHING;
|
int mActiveProcState = ProcessStats.STATE_NOTHING;
|
||||||
long mActiveStartUptime;
|
long mActiveStartUptime;
|
||||||
long mActiveDuration;
|
long mActiveDuration;
|
||||||
DurationsTable mActiveDurations;
|
DurationsTable mActiveDurations;
|
||||||
|
|
||||||
SourceState(SourceKey key) {
|
SourceState(@NonNull ProcessStats processStats, @Nullable AssociationState associationState,
|
||||||
|
@NonNull ProcessState targetProcess, SourceKey key) {
|
||||||
|
mProcessStats = processStats;
|
||||||
|
mAssociationState = associationState;
|
||||||
|
mTargetProcess = targetProcess;
|
||||||
mKey = key;
|
mKey = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public AssociationState getAssociationState() {
|
public AssociationState getAssociationState() {
|
||||||
return AssociationState.this;
|
return mAssociationState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getProcessName() {
|
public String getProcessName() {
|
||||||
@@ -86,7 +101,20 @@ public final class AssociationState {
|
|||||||
return mKey.mUid;
|
return mKey.mUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private SourceState getCommonSourceState(boolean createIfNeeded) {
|
||||||
|
if (mCommonSourceState == null) {
|
||||||
|
if (createIfNeeded) {
|
||||||
|
mCommonSourceState = mTargetProcess.getOrCreateSourceState(mKey);
|
||||||
|
} else {
|
||||||
|
Slog.wtf(TAG, "Unable to find common source state for " + mKey.mProcess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mCommonSourceState;
|
||||||
|
}
|
||||||
|
|
||||||
public void trackProcState(int procState, int seq, long now) {
|
public void trackProcState(int procState, int seq, long now) {
|
||||||
|
final int processState = procState;
|
||||||
procState = ProcessState.PROCESS_STATE_TO_STATE[procState];
|
procState = ProcessState.PROCESS_STATE_TO_STATE[procState];
|
||||||
if (seq != mProcStateSeq) {
|
if (seq != mProcStateSeq) {
|
||||||
mProcStateSeq = seq;
|
mProcStateSeq = seq;
|
||||||
@@ -102,30 +130,81 @@ public final class AssociationState {
|
|||||||
if (!mInTrackingList) {
|
if (!mInTrackingList) {
|
||||||
mInTrackingList = true;
|
mInTrackingList = true;
|
||||||
mTrackingUptime = now;
|
mTrackingUptime = now;
|
||||||
mProcessStats.mTrackingAssociations.add(this);
|
if (mAssociationState != null) {
|
||||||
|
mProcessStats.mTrackingAssociations.add(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mAssociationState != null) {
|
||||||
|
final SourceState commonSource = getCommonSourceState(true);
|
||||||
|
if (commonSource != null) {
|
||||||
|
commonSource.trackProcState(processState, seq, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long start() {
|
||||||
|
final long now = start(-1);
|
||||||
|
if (mAssociationState != null) {
|
||||||
|
final SourceState commonSource = getCommonSourceState(true);
|
||||||
|
if (commonSource != null) {
|
||||||
|
commonSource.start(now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
|
||||||
|
long start(long now) {
|
||||||
|
mNesting++;
|
||||||
|
if (mNesting == 1) {
|
||||||
|
if (now < 0) {
|
||||||
|
now = SystemClock.uptimeMillis();
|
||||||
|
}
|
||||||
|
mCount++;
|
||||||
|
mStartUptime = now;
|
||||||
|
}
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
mNesting--;
|
final long now = stop(-1);
|
||||||
if (mNesting == 0) {
|
if (mAssociationState != null) {
|
||||||
final long now = SystemClock.uptimeMillis();
|
final SourceState commonSource = getCommonSourceState(false);
|
||||||
mDuration += now - mStartUptime;
|
if (commonSource != null) {
|
||||||
stopTracking(now);
|
commonSource.stop(now);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long stop(long now) {
|
||||||
|
mNesting--;
|
||||||
|
if (mNesting == 0) {
|
||||||
|
if (now < 0) {
|
||||||
|
now = SystemClock.uptimeMillis();
|
||||||
|
}
|
||||||
|
mDuration += now - mStartUptime;
|
||||||
|
stopTracking(now);
|
||||||
|
}
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
|
||||||
void startActive(long now) {
|
void startActive(long now) {
|
||||||
|
boolean startActive = false;
|
||||||
if (mInTrackingList) {
|
if (mInTrackingList) {
|
||||||
if (mActiveStartUptime == 0) {
|
if (mActiveStartUptime == 0) {
|
||||||
mActiveStartUptime = now;
|
mActiveStartUptime = now;
|
||||||
|
mActiveNesting++;
|
||||||
mActiveCount++;
|
mActiveCount++;
|
||||||
AssociationState.this.mTotalActiveNesting++;
|
startActive = true;
|
||||||
if (AssociationState.this.mTotalActiveNesting == 1) {
|
if (mAssociationState != null) {
|
||||||
AssociationState.this.mTotalActiveCount++;
|
mAssociationState.mTotalActiveNesting++;
|
||||||
AssociationState.this.mTotalActiveStartUptime = now;
|
if (mAssociationState.mTotalActiveNesting == 1) {
|
||||||
|
mAssociationState.mTotalActiveCount++;
|
||||||
|
mAssociationState.mTotalActiveStartUptime = now;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if (mAssociationState == null) {
|
||||||
|
mActiveNesting++;
|
||||||
}
|
}
|
||||||
if (mActiveProcState != mProcState) {
|
if (mActiveProcState != mProcState) {
|
||||||
if (mActiveProcState != ProcessStats.STATE_NOTHING) {
|
if (mActiveProcState != ProcessStats.STATE_NOTHING) {
|
||||||
@@ -133,6 +212,9 @@ public final class AssociationState {
|
|||||||
// so far and switch tracking to the new proc state.
|
// so far and switch tracking to the new proc state.
|
||||||
final long addedDuration = mActiveDuration + now - mActiveStartUptime;
|
final long addedDuration = mActiveDuration + now - mActiveStartUptime;
|
||||||
mActiveStartUptime = now;
|
mActiveStartUptime = now;
|
||||||
|
if (mAssociationState != null) {
|
||||||
|
startActive = true;
|
||||||
|
}
|
||||||
if (addedDuration != 0) {
|
if (addedDuration != 0) {
|
||||||
if (mActiveDurations == null) {
|
if (mActiveDurations == null) {
|
||||||
makeDurations();
|
makeDurations();
|
||||||
@@ -146,68 +228,233 @@ public final class AssociationState {
|
|||||||
} else {
|
} else {
|
||||||
Slog.wtf(TAG, "startActive while not tracking: " + this);
|
Slog.wtf(TAG, "startActive while not tracking: " + this);
|
||||||
}
|
}
|
||||||
|
if (mAssociationState != null) {
|
||||||
|
final SourceState commonSource = getCommonSourceState(true);
|
||||||
|
if (commonSource != null && startActive) {
|
||||||
|
commonSource.startActive(now);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopActive(long now) {
|
void stopActive(long now) {
|
||||||
|
boolean stopActive = false;
|
||||||
if (mActiveStartUptime != 0) {
|
if (mActiveStartUptime != 0) {
|
||||||
if (!mInTrackingList) {
|
if (!mInTrackingList && mAssociationState != null) {
|
||||||
Slog.wtf(TAG, "stopActive while not tracking: " + this);
|
Slog.wtf(TAG, "stopActive while not tracking: " + this);
|
||||||
}
|
}
|
||||||
|
mActiveNesting--;
|
||||||
final long addedDuration = now - mActiveStartUptime;
|
final long addedDuration = now - mActiveStartUptime;
|
||||||
mActiveStartUptime = 0;
|
mActiveStartUptime = mAssociationState != null || mActiveNesting == 0 ? 0 : now;
|
||||||
|
stopActive = mActiveStartUptime == 0;
|
||||||
if (mActiveDurations != null) {
|
if (mActiveDurations != null) {
|
||||||
mActiveDurations.addDuration(mActiveProcState, addedDuration);
|
mActiveDurations.addDuration(mActiveProcState, addedDuration);
|
||||||
} else {
|
} else {
|
||||||
mActiveDuration += addedDuration;
|
mActiveDuration += addedDuration;
|
||||||
}
|
}
|
||||||
AssociationState.this.mTotalActiveNesting--;
|
if (mAssociationState != null) {
|
||||||
if (AssociationState.this.mTotalActiveNesting == 0) {
|
mAssociationState.mTotalActiveNesting--;
|
||||||
AssociationState.this.mTotalActiveDuration += now
|
if (mAssociationState.mTotalActiveNesting == 0) {
|
||||||
- AssociationState.this.mTotalActiveStartUptime;
|
mAssociationState.mTotalActiveDuration += now
|
||||||
AssociationState.this.mTotalActiveStartUptime = 0;
|
- mAssociationState.mTotalActiveStartUptime;
|
||||||
if (VALIDATE_TIMES) {
|
mAssociationState.mTotalActiveStartUptime = 0;
|
||||||
if (mActiveDuration > AssociationState.this.mTotalActiveDuration) {
|
if (VALIDATE_TIMES) {
|
||||||
RuntimeException ex = new RuntimeException();
|
if (mActiveDuration > mAssociationState.mTotalActiveDuration) {
|
||||||
ex.fillInStackTrace();
|
RuntimeException ex = new RuntimeException();
|
||||||
Slog.w(TAG, "Source act duration " + mActiveDurations
|
ex.fillInStackTrace();
|
||||||
+ " exceeds total " + AssociationState.this.mTotalActiveDuration
|
Slog.w(TAG, "Source act duration " + mActiveDurations
|
||||||
+ " in procstate " + mActiveProcState + " in source "
|
+ " exceeds total " + mAssociationState.mTotalActiveDuration
|
||||||
+ mKey.mProcess + " to assoc "
|
+ " in procstate " + mActiveProcState + " in source "
|
||||||
+ AssociationState.this.mName, ex);
|
+ mKey.mProcess + " to assoc "
|
||||||
}
|
+ mAssociationState.mName, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mAssociationState != null) {
|
||||||
|
final SourceState commonSource = getCommonSourceState(false);
|
||||||
|
if (commonSource != null && stopActive) {
|
||||||
|
commonSource.stopActive(now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean stopActiveIfNecessary(int curSeq, long now) {
|
||||||
|
if (mProcStateSeq != curSeq || mProcState >= ProcessStats.STATE_HOME) {
|
||||||
|
// If this association did not get touched the last time we computed
|
||||||
|
// process states, or its state ended up down in cached, then we no
|
||||||
|
// longer have a reason to track it at all.
|
||||||
|
stopActive(now);
|
||||||
|
stopTrackingProcState();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopTrackingProcState() {
|
||||||
|
mInTrackingList = false;
|
||||||
|
mProcState = ProcessStats.STATE_NOTHING;
|
||||||
|
if (mAssociationState != null) {
|
||||||
|
final SourceState commonSource = getCommonSourceState(false);
|
||||||
|
if (commonSource != null) {
|
||||||
|
commonSource.stopTrackingProcState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isInUse() {
|
||||||
|
return mNesting > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetSafely(long now) {
|
||||||
|
if (isInUse()) {
|
||||||
|
mCount = 1;
|
||||||
|
mStartUptime = now;
|
||||||
|
mDuration = 0;
|
||||||
|
if (mActiveStartUptime > 0) {
|
||||||
|
mActiveCount = 1;
|
||||||
|
mActiveStartUptime = now;
|
||||||
|
} else {
|
||||||
|
mActiveCount = 0;
|
||||||
|
}
|
||||||
|
mActiveDuration = 0;
|
||||||
|
mActiveDurations = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void commitStateTime(long nowUptime) {
|
||||||
|
if (mNesting > 0) {
|
||||||
|
mDuration += nowUptime - mStartUptime;
|
||||||
|
mStartUptime = nowUptime;
|
||||||
|
}
|
||||||
|
if (mActiveStartUptime > 0) {
|
||||||
|
final long addedDuration = nowUptime - mActiveStartUptime;
|
||||||
|
mActiveStartUptime = nowUptime;
|
||||||
|
if (mActiveDurations != null) {
|
||||||
|
mActiveDurations.addDuration(mActiveProcState, addedDuration);
|
||||||
|
} else {
|
||||||
|
mActiveDuration += addedDuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void makeDurations() {
|
void makeDurations() {
|
||||||
mActiveDurations = new DurationsTable(mProcessStats.mTableData);
|
mActiveDurations = new DurationsTable(mProcessStats.mTableData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopTracking(long now) {
|
private void stopTracking(long now) {
|
||||||
AssociationState.this.mTotalNesting--;
|
if (mAssociationState != null) {
|
||||||
if (AssociationState.this.mTotalNesting == 0) {
|
mAssociationState.mTotalNesting--;
|
||||||
AssociationState.this.mTotalDuration += now
|
if (mAssociationState.mTotalNesting == 0) {
|
||||||
- AssociationState.this.mTotalStartUptime;
|
mAssociationState.mTotalDuration += now
|
||||||
|
- mAssociationState.mTotalStartUptime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stopActive(now);
|
stopActive(now);
|
||||||
if (mInTrackingList) {
|
if (mInTrackingList) {
|
||||||
mInTrackingList = false;
|
mInTrackingList = false;
|
||||||
mProcState = ProcessStats.STATE_NOTHING;
|
mProcState = ProcessStats.STATE_NOTHING;
|
||||||
// Do a manual search for where to remove, since these objects will typically
|
if (mAssociationState != null) {
|
||||||
// be towards the end of the array.
|
// Do a manual search for where to remove, since these objects will typically
|
||||||
final ArrayList<SourceState> list = mProcessStats.mTrackingAssociations;
|
// be towards the end of the array.
|
||||||
for (int i = list.size() - 1; i >= 0; i--) {
|
final ArrayList<SourceState> list = mProcessStats.mTrackingAssociations;
|
||||||
if (list.get(i) == this) {
|
for (int i = list.size() - 1; i >= 0; i--) {
|
||||||
list.remove(i);
|
if (list.get(i) == this) {
|
||||||
return;
|
list.remove(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Slog.wtf(TAG, "Stop tracking didn't find in tracking list: " + this);
|
||||||
}
|
}
|
||||||
Slog.wtf(TAG, "Stop tracking didn't find in tracking list: " + this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add(SourceState otherSrc) {
|
||||||
|
mCount += otherSrc.mCount;
|
||||||
|
mDuration += otherSrc.mDuration;
|
||||||
|
mActiveCount += otherSrc.mActiveCount;
|
||||||
|
if (otherSrc.mActiveDuration != 0 || otherSrc.mActiveDurations != null) {
|
||||||
|
// Only need to do anything if the other one has some duration data.
|
||||||
|
if (mActiveDurations != null) {
|
||||||
|
// If the target already has multiple durations, just add in whatever
|
||||||
|
// we have in the other.
|
||||||
|
if (otherSrc.mActiveDurations != null) {
|
||||||
|
mActiveDurations.addDurations(otherSrc.mActiveDurations);
|
||||||
|
} else {
|
||||||
|
mActiveDurations.addDuration(otherSrc.mActiveProcState,
|
||||||
|
otherSrc.mActiveDuration);
|
||||||
|
}
|
||||||
|
} else if (otherSrc.mActiveDurations != null) {
|
||||||
|
// The other one has multiple durations, but we don't. Expand to
|
||||||
|
// multiple durations and copy over.
|
||||||
|
makeDurations();
|
||||||
|
mActiveDurations.addDurations(otherSrc.mActiveDurations);
|
||||||
|
if (mActiveDuration != 0) {
|
||||||
|
mActiveDurations.addDuration(mActiveProcState, mActiveDuration);
|
||||||
|
mActiveDuration = 0;
|
||||||
|
mActiveProcState = ProcessStats.STATE_NOTHING;
|
||||||
|
}
|
||||||
|
} else if (mActiveDuration != 0) {
|
||||||
|
// Both have a single inline duration... we can either add them together,
|
||||||
|
// or need to expand to multiple durations.
|
||||||
|
if (mActiveProcState == otherSrc.mActiveProcState) {
|
||||||
|
mActiveDuration += otherSrc.mActiveDuration;
|
||||||
|
} else {
|
||||||
|
// The two have durations with different proc states, need to turn
|
||||||
|
// in to multiple durations.
|
||||||
|
makeDurations();
|
||||||
|
mActiveDurations.addDuration(mActiveProcState, mActiveDuration);
|
||||||
|
mActiveDurations.addDuration(otherSrc.mActiveProcState,
|
||||||
|
otherSrc.mActiveDuration);
|
||||||
|
mActiveDuration = 0;
|
||||||
|
mActiveProcState = ProcessStats.STATE_NOTHING;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The other one has a duration, and we know the target doesn't. Copy over.
|
||||||
|
mActiveProcState = otherSrc.mActiveProcState;
|
||||||
|
mActiveDuration = otherSrc.mActiveDuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
out.writeInt(mCount);
|
||||||
|
out.writeLong(mDuration);
|
||||||
|
out.writeInt(mActiveCount);
|
||||||
|
if (mActiveDurations != null) {
|
||||||
|
out.writeInt(1);
|
||||||
|
mActiveDurations.writeToParcel(out);
|
||||||
|
} else {
|
||||||
|
out.writeInt(0);
|
||||||
|
out.writeInt(mActiveProcState);
|
||||||
|
out.writeLong(mActiveDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
String readFromParcel(Parcel in) {
|
||||||
|
mCount = in.readInt();
|
||||||
|
mDuration = in.readLong();
|
||||||
|
mActiveCount = in.readInt();
|
||||||
|
if (in.readInt() != 0) {
|
||||||
|
makeDurations();
|
||||||
|
if (!mActiveDurations.readFromParcel(in)) {
|
||||||
|
return "Duration table corrupt: " + mKey + " <- " + toString();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mActiveProcState = in.readInt();
|
||||||
|
mActiveDuration = in.readLong();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder(64);
|
StringBuilder sb = new StringBuilder(64);
|
||||||
@@ -222,7 +469,7 @@ public final class AssociationState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class SourceDumpContainer {
|
static final class SourceDumpContainer {
|
||||||
public final SourceState mState;
|
public final SourceState mState;
|
||||||
public long mTotalTime;
|
public long mTotalTime;
|
||||||
public long mActiveTime;
|
public long mActiveTime;
|
||||||
@@ -256,6 +503,18 @@ public final class AssociationState {
|
|||||||
mPackage = pkg;
|
mPackage = pkg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceKey(ProcessStats stats, Parcel in, int parcelVersion) {
|
||||||
|
mUid = in.readInt();
|
||||||
|
mProcess = stats.readCommonString(in, parcelVersion);
|
||||||
|
mPackage = stats.readCommonString(in, parcelVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToParcel(ProcessStats stats, Parcel out) {
|
||||||
|
out.writeInt(mUid);
|
||||||
|
stats.writeCommonString(out, mProcess);
|
||||||
|
stats.writeCommonString(out, mPackage);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (!(o instanceof SourceKey)) {
|
if (!(o instanceof SourceKey)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -347,14 +606,11 @@ public final class AssociationState {
|
|||||||
}
|
}
|
||||||
if (src == null) {
|
if (src == null) {
|
||||||
SourceKey key = new SourceKey(uid, processName, packageName);
|
SourceKey key = new SourceKey(uid, processName, packageName);
|
||||||
src = new SourceState(key);
|
src = new SourceState(mProcessStats, this, mProc, key);
|
||||||
mSources.put(key, src);
|
mSources.put(key, src);
|
||||||
}
|
}
|
||||||
src.mNesting++;
|
final long now = src.start();
|
||||||
if (src.mNesting == 1) {
|
if (now > 0) {
|
||||||
final long now = SystemClock.uptimeMillis();
|
|
||||||
src.mCount++;
|
|
||||||
src.mStartUptime = now;
|
|
||||||
mTotalNesting++;
|
mTotalNesting++;
|
||||||
if (mTotalNesting == 1) {
|
if (mTotalNesting == 1) {
|
||||||
mTotalCount++;
|
mTotalCount++;
|
||||||
@@ -376,7 +632,7 @@ public final class AssociationState {
|
|||||||
SourceState mySrc = mSources.get(key);
|
SourceState mySrc = mSources.get(key);
|
||||||
boolean newSrc = false;
|
boolean newSrc = false;
|
||||||
if (mySrc == null) {
|
if (mySrc == null) {
|
||||||
mySrc = new SourceState(key);
|
mySrc = new SourceState(mProcessStats, this, mProc, key);
|
||||||
mSources.put(key, mySrc);
|
mSources.put(key, mySrc);
|
||||||
newSrc = true;
|
newSrc = true;
|
||||||
}
|
}
|
||||||
@@ -412,53 +668,7 @@ public final class AssociationState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mySrc.mCount += otherSrc.mCount;
|
mySrc.add(otherSrc);
|
||||||
mySrc.mDuration += otherSrc.mDuration;
|
|
||||||
mySrc.mActiveCount += otherSrc.mActiveCount;
|
|
||||||
if (otherSrc.mActiveDuration != 0 || otherSrc.mActiveDurations != null) {
|
|
||||||
// Only need to do anything if the other one has some duration data.
|
|
||||||
if (mySrc.mActiveDurations != null) {
|
|
||||||
// If the target already has multiple durations, just add in whatever
|
|
||||||
// we have in the other.
|
|
||||||
if (otherSrc.mActiveDurations != null) {
|
|
||||||
mySrc.mActiveDurations.addDurations(otherSrc.mActiveDurations);
|
|
||||||
} else {
|
|
||||||
mySrc.mActiveDurations.addDuration(otherSrc.mActiveProcState,
|
|
||||||
otherSrc.mActiveDuration);
|
|
||||||
}
|
|
||||||
} else if (otherSrc.mActiveDurations != null) {
|
|
||||||
// The other one has multiple durations, but we don't. Expand to
|
|
||||||
// multiple durations and copy over.
|
|
||||||
mySrc.makeDurations();
|
|
||||||
mySrc.mActiveDurations.addDurations(otherSrc.mActiveDurations);
|
|
||||||
if (mySrc.mActiveDuration != 0) {
|
|
||||||
mySrc.mActiveDurations.addDuration(mySrc.mActiveProcState,
|
|
||||||
mySrc.mActiveDuration);
|
|
||||||
mySrc.mActiveDuration = 0;
|
|
||||||
mySrc.mActiveProcState = ProcessStats.STATE_NOTHING;
|
|
||||||
}
|
|
||||||
} else if (mySrc.mActiveDuration != 0) {
|
|
||||||
// Both have a single inline duration... we can either add them together,
|
|
||||||
// or need to expand to multiple durations.
|
|
||||||
if (mySrc.mActiveProcState == otherSrc.mActiveProcState) {
|
|
||||||
mySrc.mActiveDuration += otherSrc.mActiveDuration;
|
|
||||||
} else {
|
|
||||||
// The two have durations with different proc states, need to turn
|
|
||||||
// in to multiple durations.
|
|
||||||
mySrc.makeDurations();
|
|
||||||
mySrc.mActiveDurations.addDuration(mySrc.mActiveProcState,
|
|
||||||
mySrc.mActiveDuration);
|
|
||||||
mySrc.mActiveDurations.addDuration(otherSrc.mActiveProcState,
|
|
||||||
otherSrc.mActiveDuration);
|
|
||||||
mySrc.mActiveDuration = 0;
|
|
||||||
mySrc.mActiveProcState = ProcessStats.STATE_NOTHING;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// The other one has a duration, and we know the target doesn't. Copy over.
|
|
||||||
mySrc.mActiveProcState = otherSrc.mActiveProcState;
|
|
||||||
mySrc.mActiveDuration = otherSrc.mActiveDuration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,18 +684,8 @@ public final class AssociationState {
|
|||||||
// We have some active sources... clear out everything but those.
|
// We have some active sources... clear out everything but those.
|
||||||
for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) {
|
for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) {
|
||||||
SourceState src = mSources.valueAt(isrc);
|
SourceState src = mSources.valueAt(isrc);
|
||||||
if (src.mNesting > 0) {
|
if (src.isInUse()) {
|
||||||
src.mCount = 1;
|
src.resetSafely(now);
|
||||||
src.mStartUptime = now;
|
|
||||||
src.mDuration = 0;
|
|
||||||
if (src.mActiveStartUptime > 0) {
|
|
||||||
src.mActiveCount = 1;
|
|
||||||
src.mActiveStartUptime = now;
|
|
||||||
} else {
|
|
||||||
src.mActiveCount = 0;
|
|
||||||
}
|
|
||||||
src.mActiveDuration = 0;
|
|
||||||
src.mActiveDurations = null;
|
|
||||||
} else {
|
} else {
|
||||||
mSources.removeAt(isrc);
|
mSources.removeAt(isrc);
|
||||||
}
|
}
|
||||||
@@ -512,20 +712,8 @@ public final class AssociationState {
|
|||||||
for (int isrc = 0; isrc < NSRC; isrc++) {
|
for (int isrc = 0; isrc < NSRC; isrc++) {
|
||||||
final SourceKey key = mSources.keyAt(isrc);
|
final SourceKey key = mSources.keyAt(isrc);
|
||||||
final SourceState src = mSources.valueAt(isrc);
|
final SourceState src = mSources.valueAt(isrc);
|
||||||
out.writeInt(key.mUid);
|
key.writeToParcel(stats, out);
|
||||||
stats.writeCommonString(out, key.mProcess);
|
src.writeToParcel(out, 0);
|
||||||
stats.writeCommonString(out, key.mPackage);
|
|
||||||
out.writeInt(src.mCount);
|
|
||||||
out.writeLong(src.mDuration);
|
|
||||||
out.writeInt(src.mActiveCount);
|
|
||||||
if (src.mActiveDurations != null) {
|
|
||||||
out.writeInt(1);
|
|
||||||
src.mActiveDurations.writeToParcel(out);
|
|
||||||
} else {
|
|
||||||
out.writeInt(0);
|
|
||||||
out.writeInt(src.mActiveProcState);
|
|
||||||
out.writeLong(src.mActiveDuration);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,22 +731,11 @@ public final class AssociationState {
|
|||||||
return "Association with bad src count: " + NSRC;
|
return "Association with bad src count: " + NSRC;
|
||||||
}
|
}
|
||||||
for (int isrc = 0; isrc < NSRC; isrc++) {
|
for (int isrc = 0; isrc < NSRC; isrc++) {
|
||||||
final int uid = in.readInt();
|
final SourceKey key = new SourceKey(stats, in, parcelVersion);
|
||||||
final String procName = stats.readCommonString(in, parcelVersion);
|
final SourceState src = new SourceState(mProcessStats, this, mProc, key);
|
||||||
final String pkgName = stats.readCommonString(in, parcelVersion);
|
final String errMsg = src.readFromParcel(in);
|
||||||
final SourceKey key = new SourceKey(uid, procName, pkgName);
|
if (errMsg != null) {
|
||||||
final SourceState src = new SourceState(key);
|
return errMsg;
|
||||||
src.mCount = in.readInt();
|
|
||||||
src.mDuration = in.readLong();
|
|
||||||
src.mActiveCount = in.readInt();
|
|
||||||
if (in.readInt() != 0) {
|
|
||||||
src.makeDurations();
|
|
||||||
if (!src.mActiveDurations.readFromParcel(in)) {
|
|
||||||
return "Duration table corrupt: " + key + " <- " + src;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
src.mActiveProcState = in.readInt();
|
|
||||||
src.mActiveDuration = in.readLong();
|
|
||||||
}
|
}
|
||||||
if (VALIDATE_TIMES) {
|
if (VALIDATE_TIMES) {
|
||||||
if (src.mDuration > mTotalDuration) {
|
if (src.mDuration > mTotalDuration) {
|
||||||
@@ -585,19 +762,7 @@ public final class AssociationState {
|
|||||||
if (isInUse()) {
|
if (isInUse()) {
|
||||||
for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) {
|
for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) {
|
||||||
SourceState src = mSources.valueAt(isrc);
|
SourceState src = mSources.valueAt(isrc);
|
||||||
if (src.mNesting > 0) {
|
src.commitStateTime(nowUptime);
|
||||||
src.mDuration += nowUptime - src.mStartUptime;
|
|
||||||
src.mStartUptime = nowUptime;
|
|
||||||
}
|
|
||||||
if (src.mActiveStartUptime > 0) {
|
|
||||||
final long addedDuration = nowUptime - src.mActiveStartUptime;
|
|
||||||
src.mActiveStartUptime = nowUptime;
|
|
||||||
if (src.mActiveDurations != null) {
|
|
||||||
src.mActiveDurations.addDuration(src.mActiveProcState, addedDuration);
|
|
||||||
} else {
|
|
||||||
src.mActiveDuration += addedDuration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (mTotalNesting > 0) {
|
if (mTotalNesting > 0) {
|
||||||
mTotalDuration += nowUptime - mTotalStartUptime;
|
mTotalDuration += nowUptime - mTotalStartUptime;
|
||||||
@@ -644,12 +809,12 @@ public final class AssociationState {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
public ArrayList<Pair<SourceKey, SourceDumpContainer>> createSortedAssociations(long now,
|
static ArrayList<Pair<SourceKey, SourceDumpContainer>> createSortedAssociations(long now,
|
||||||
long totalTime) {
|
long totalTime, ArrayMap<SourceKey, SourceState> inSources) {
|
||||||
final int NSRC = mSources.size();
|
final int numOfSources = inSources.size();
|
||||||
ArrayList<Pair<SourceKey, SourceDumpContainer>> sources = new ArrayList<>(NSRC);
|
ArrayList<Pair<SourceKey, SourceDumpContainer>> sources = new ArrayList<>(numOfSources);
|
||||||
for (int isrc = 0; isrc < NSRC; isrc++) {
|
for (int isrc = 0; isrc < numOfSources; isrc++) {
|
||||||
final SourceState src = mSources.valueAt(isrc);
|
final SourceState src = inSources.valueAt(isrc);
|
||||||
final SourceDumpContainer cont = new SourceDumpContainer(src);
|
final SourceDumpContainer cont = new SourceDumpContainer(src);
|
||||||
long duration = src.mDuration;
|
long duration = src.mDuration;
|
||||||
if (src.mNesting > 0) {
|
if (src.mNesting > 0) {
|
||||||
@@ -660,7 +825,7 @@ public final class AssociationState {
|
|||||||
if (cont.mActiveTime < 0) {
|
if (cont.mActiveTime < 0) {
|
||||||
cont.mActiveTime = -cont.mActiveTime;
|
cont.mActiveTime = -cont.mActiveTime;
|
||||||
}
|
}
|
||||||
sources.add(new Pair<>(mSources.keyAt(isrc), cont));
|
sources.add(new Pair<>(inSources.keyAt(isrc), cont));
|
||||||
}
|
}
|
||||||
Collections.sort(sources, ASSOCIATION_COMPARATOR);
|
Collections.sort(sources, ASSOCIATION_COMPARATOR);
|
||||||
return sources;
|
return sources;
|
||||||
@@ -722,6 +887,14 @@ public final class AssociationState {
|
|||||||
TimeUtils.formatDuration(mTotalStartUptime, now, pw);
|
TimeUtils.formatDuration(mTotalStartUptime, now, pw);
|
||||||
pw.println();
|
pw.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dumpSources(pw, prefix, prefixInner, prefixInnerInner, sources, now, totalTime,
|
||||||
|
reqPackage, dumpDetails, dumpAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dumpSources(PrintWriter pw, String prefix, String prefixInner,
|
||||||
|
String prefixInnerInner, ArrayList<Pair<SourceKey, SourceDumpContainer>> sources,
|
||||||
|
long now, long totalTime, String reqPackage, boolean dumpDetails, boolean dumpAll) {
|
||||||
final int NSRC = sources.size();
|
final int NSRC = sources.size();
|
||||||
for (int isrc = 0; isrc < NSRC; isrc++) {
|
for (int isrc = 0; isrc < NSRC; isrc++) {
|
||||||
final SourceKey key = sources.get(isrc).first;
|
final SourceKey key = sources.get(isrc).first;
|
||||||
@@ -826,7 +999,7 @@ public final class AssociationState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dumpActiveDurationSummary(PrintWriter pw, final SourceState src, long totalTime,
|
static void dumpActiveDurationSummary(PrintWriter pw, final SourceState src, long totalTime,
|
||||||
long now, boolean dumpAll) {
|
long now, boolean dumpAll) {
|
||||||
long duration = dumpTime(null, null, src, totalTime, now, false, false);
|
long duration = dumpTime(null, null, src, totalTime, now, false, false);
|
||||||
final boolean isRunning = duration < 0;
|
final boolean isRunning = duration < 0;
|
||||||
@@ -846,8 +1019,8 @@ public final class AssociationState {
|
|||||||
pw.println();
|
pw.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
long dumpTime(PrintWriter pw, String prefix, final SourceState src, long overallTime, long now,
|
static long dumpTime(PrintWriter pw, String prefix, final SourceState src, long overallTime,
|
||||||
boolean dumpDetails, boolean dumpAll) {
|
long now, boolean dumpDetails, boolean dumpAll) {
|
||||||
long totalTime = 0;
|
long totalTime = 0;
|
||||||
boolean isRunning = false;
|
boolean isRunning = false;
|
||||||
for (int iprocstate = 0; iprocstate < ProcessStats.STATE_COUNT; iprocstate++) {
|
for (int iprocstate = 0; iprocstate < ProcessStats.STATE_COUNT; iprocstate++) {
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ import android.util.proto.ProtoOutputStream;
|
|||||||
import android.util.proto.ProtoUtils;
|
import android.util.proto.ProtoUtils;
|
||||||
|
|
||||||
import com.android.internal.app.ProcessMap;
|
import com.android.internal.app.ProcessMap;
|
||||||
|
import com.android.internal.app.procstats.AssociationState.SourceKey;
|
||||||
|
import com.android.internal.app.procstats.AssociationState.SourceState;
|
||||||
import com.android.internal.app.procstats.ProcessStats.PackageState;
|
import com.android.internal.app.procstats.ProcessStats.PackageState;
|
||||||
import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
|
import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
|
||||||
import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
|
import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
|
||||||
@@ -162,6 +164,11 @@ public final class ProcessState {
|
|||||||
// Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful.
|
// Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful.
|
||||||
private long mTmpTotalTime;
|
private long mTmpTotalTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The combined source states which has or had an association with this process.
|
||||||
|
*/
|
||||||
|
ArrayMap<SourceKey, SourceState> mCommonSources;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new top-level process state, for the initial case where there is only
|
* Create a new top-level process state, for the initial case where there is only
|
||||||
* a single package running in a process. The initial state is not running.
|
* a single package running in a process. The initial state is not running.
|
||||||
@@ -267,6 +274,21 @@ public final class ProcessState {
|
|||||||
addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
|
addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
|
||||||
other.mAvgCachedKillPss, other.mMaxCachedKillPss);
|
other.mAvgCachedKillPss, other.mMaxCachedKillPss);
|
||||||
}
|
}
|
||||||
|
if (other.mCommonSources != null) {
|
||||||
|
if (mCommonSources == null) {
|
||||||
|
mCommonSources = new ArrayMap<>();
|
||||||
|
}
|
||||||
|
int size = other.mCommonSources.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
final SourceKey key = other.mCommonSources.keyAt(i);
|
||||||
|
SourceState state = mCommonSources.get(key);
|
||||||
|
if (state == null) {
|
||||||
|
state = new SourceState(mStats, null, this, key);
|
||||||
|
mCommonSources.put(key, state);
|
||||||
|
}
|
||||||
|
state.add(other.mCommonSources.valueAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetSafely(long now) {
|
public void resetSafely(long now) {
|
||||||
@@ -278,6 +300,17 @@ public final class ProcessState {
|
|||||||
mNumExcessiveCpu = 0;
|
mNumExcessiveCpu = 0;
|
||||||
mNumCachedKill = 0;
|
mNumCachedKill = 0;
|
||||||
mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
|
mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
|
||||||
|
// Reset the combine source state.
|
||||||
|
if (mCommonSources != null) {
|
||||||
|
for (int ip = mCommonSources.size() - 1; ip >= 0; ip--) {
|
||||||
|
final SourceState state = mCommonSources.valueAt(ip);
|
||||||
|
if (state.isInUse()) {
|
||||||
|
state.resetSafely(now);
|
||||||
|
} else {
|
||||||
|
mCommonSources.removeAt(ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void makeDead() {
|
public void makeDead() {
|
||||||
@@ -308,9 +341,18 @@ public final class ProcessState {
|
|||||||
out.writeLong(mAvgCachedKillPss);
|
out.writeLong(mAvgCachedKillPss);
|
||||||
out.writeLong(mMaxCachedKillPss);
|
out.writeLong(mMaxCachedKillPss);
|
||||||
}
|
}
|
||||||
|
// The combined source state of all associations.
|
||||||
|
final int numOfSources = mCommonSources != null ? mCommonSources.size() : 0;
|
||||||
|
out.writeInt(numOfSources);
|
||||||
|
for (int i = 0; i < numOfSources; i++) {
|
||||||
|
final SourceKey key = mCommonSources.keyAt(i);
|
||||||
|
final SourceState src = mCommonSources.valueAt(i);
|
||||||
|
key.writeToParcel(mStats, out);
|
||||||
|
src.writeToParcel(out, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean readFromParcel(Parcel in, boolean fully) {
|
boolean readFromParcel(Parcel in, int version, boolean fully) {
|
||||||
boolean multiPackage = in.readInt() != 0;
|
boolean multiPackage = in.readInt() != 0;
|
||||||
if (fully) {
|
if (fully) {
|
||||||
mMultiPackage = multiPackage;
|
mMultiPackage = multiPackage;
|
||||||
@@ -337,6 +379,19 @@ public final class ProcessState {
|
|||||||
} else {
|
} else {
|
||||||
mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
|
mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The combined source state of all associations.
|
||||||
|
final int numOfSources = in.readInt();
|
||||||
|
if (numOfSources > 0) {
|
||||||
|
mCommonSources = new ArrayMap<>(numOfSources);
|
||||||
|
for (int i = 0; i < numOfSources; i++) {
|
||||||
|
final SourceKey key = new SourceKey(mStats, in, version);
|
||||||
|
final SourceState src = new SourceState(mStats, null, this, key);
|
||||||
|
src.readFromParcel(in);
|
||||||
|
mCommonSources.put(key, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,6 +488,12 @@ public final class ProcessState {
|
|||||||
mTotalRunningStartTime = now;
|
mTotalRunningStartTime = now;
|
||||||
}
|
}
|
||||||
mStartTime = now;
|
mStartTime = now;
|
||||||
|
if (mCommonSources != null) {
|
||||||
|
for (int ip = mCommonSources.size() - 1; ip >= 0; ip--) {
|
||||||
|
final SourceState src = mCommonSources.valueAt(ip);
|
||||||
|
src.commitStateTime(now);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incActiveServices(String serviceName) {
|
public void incActiveServices(String serviceName) {
|
||||||
@@ -722,6 +783,18 @@ public final class ProcessState {
|
|||||||
return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM);
|
return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceState getOrCreateSourceState(SourceKey key) {
|
||||||
|
if (mCommonSources == null) {
|
||||||
|
mCommonSources = new ArrayMap<>();
|
||||||
|
}
|
||||||
|
SourceState state = mCommonSources.get(key);
|
||||||
|
if (state == null) {
|
||||||
|
state = new SourceState(mStats, null, this, key);
|
||||||
|
mCommonSources.put(key, state);
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sums up the PSS data and adds it to 'data'.
|
* Sums up the PSS data and adds it to 'data'.
|
||||||
*
|
*
|
||||||
@@ -1038,7 +1111,8 @@ public final class ProcessState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll) {
|
void dumpInternalLocked(PrintWriter pw, String prefix, String reqPackage,
|
||||||
|
long totalTime, long now, boolean dumpAll) {
|
||||||
if (dumpAll) {
|
if (dumpAll) {
|
||||||
pw.print(prefix); pw.print("myID=");
|
pw.print(prefix); pw.print("myID=");
|
||||||
pw.print(Integer.toHexString(System.identityHashCode(this)));
|
pw.print(Integer.toHexString(System.identityHashCode(this)));
|
||||||
@@ -1053,6 +1127,13 @@ public final class ProcessState {
|
|||||||
pw.print("/"); pw.print(mCommonProcess.mUid);
|
pw.print("/"); pw.print(mCommonProcess.mUid);
|
||||||
pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
|
pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
|
||||||
}
|
}
|
||||||
|
if (mCommonSources != null) {
|
||||||
|
pw.print(prefix); pw.println("Aggregated Association Sources:");
|
||||||
|
AssociationState.dumpSources(
|
||||||
|
pw, prefix + " ", prefix + " ", prefix + " ",
|
||||||
|
AssociationState.createSortedAssociations(now, totalTime, mCommonSources),
|
||||||
|
now, totalTime, reqPackage, true, dumpAll);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (mActive) {
|
if (mActive) {
|
||||||
pw.print(prefix); pw.print("mActive="); pw.println(mActive);
|
pw.print(prefix); pw.print("mActive="); pw.println(mActive);
|
||||||
@@ -1559,7 +1640,7 @@ public final class ProcessState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS,
|
mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS,
|
||||||
now, this, procToPkgMap, uidToPkgMap);
|
now, this, uidToPkgMap);
|
||||||
proto.end(token);
|
proto.end(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import android.service.procstats.ProcessStatsAssociationProto;
|
|||||||
import android.service.procstats.ProcessStatsAvailablePagesProto;
|
import android.service.procstats.ProcessStatsAvailablePagesProto;
|
||||||
import android.service.procstats.ProcessStatsPackageProto;
|
import android.service.procstats.ProcessStatsPackageProto;
|
||||||
import android.service.procstats.ProcessStatsSectionProto;
|
import android.service.procstats.ProcessStatsSectionProto;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.text.format.DateFormat;
|
import android.text.format.DateFormat;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
@@ -187,7 +186,7 @@ public final class ProcessStats implements Parcelable {
|
|||||||
{"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};
|
{"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};
|
||||||
|
|
||||||
// Current version of the parcel format.
|
// Current version of the parcel format.
|
||||||
private static final int PARCEL_VERSION = 38;
|
private static final int PARCEL_VERSION = 39;
|
||||||
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
|
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
|
||||||
private static final int MAGIC = 0x50535454;
|
private static final int MAGIC = 0x50535454;
|
||||||
|
|
||||||
@@ -1113,12 +1112,12 @@ public final class ProcessStats implements Parcelable {
|
|||||||
final long vers = in.readLong();
|
final long vers = in.readLong();
|
||||||
ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
|
ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
|
||||||
if (proc != null) {
|
if (proc != null) {
|
||||||
if (!proc.readFromParcel(in, false)) {
|
if (!proc.readFromParcel(in, version, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
proc = new ProcessState(this, pkgName, uid, vers, procName);
|
proc = new ProcessState(this, pkgName, uid, vers, procName);
|
||||||
if (!proc.readFromParcel(in, true)) {
|
if (!proc.readFromParcel(in, version, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1198,13 +1197,13 @@ public final class ProcessStats implements Parcelable {
|
|||||||
// they will find and use it from the global procs.
|
// they will find and use it from the global procs.
|
||||||
ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null;
|
ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null;
|
||||||
if (proc != null) {
|
if (proc != null) {
|
||||||
if (!proc.readFromParcel(in, false)) {
|
if (!proc.readFromParcel(in, version, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
proc = new ProcessState(commonProc, pkgName, uid, vers, procName,
|
proc = new ProcessState(commonProc, pkgName, uid, vers, procName,
|
||||||
0);
|
0);
|
||||||
if (!proc.readFromParcel(in, true)) {
|
if (!proc.readFromParcel(in, version, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1439,16 +1438,15 @@ public final class ProcessStats implements Parcelable {
|
|||||||
final int NUM = mTrackingAssociations.size();
|
final int NUM = mTrackingAssociations.size();
|
||||||
for (int i = NUM - 1; i >= 0; i--) {
|
for (int i = NUM - 1; i >= 0; i--) {
|
||||||
final AssociationState.SourceState act = mTrackingAssociations.get(i);
|
final AssociationState.SourceState act = mTrackingAssociations.get(i);
|
||||||
if (act.mProcStateSeq != curSeq || act.mProcState >= ProcessStats.STATE_HOME) {
|
if (act.stopActiveIfNecessary(curSeq, now)) {
|
||||||
// If this association did not get touched the last time we computed
|
|
||||||
// process states, or its state ended up down in cached, then we no
|
|
||||||
// longer have a reason to track it at all.
|
|
||||||
act.stopActive(now);
|
|
||||||
act.mInTrackingList = false;
|
|
||||||
act.mProcState = ProcessStats.STATE_NOTHING;
|
|
||||||
mTrackingAssociations.remove(i);
|
mTrackingAssociations.remove(i);
|
||||||
} else {
|
} else {
|
||||||
final ProcessState proc = act.getAssociationState().getProcess();
|
final AssociationState asc = act.getAssociationState();
|
||||||
|
if (asc == null) {
|
||||||
|
Slog.wtf(TAG, act.toString() + " shouldn't be in the tracking list.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final ProcessState proc = asc.getProcess();
|
||||||
if (proc != null) {
|
if (proc != null) {
|
||||||
final int procState = proc.getCombinedState() % STATE_COUNT;
|
final int procState = proc.getCombinedState() % STATE_COUNT;
|
||||||
if (act.mProcState == procState) {
|
if (act.mProcState == procState) {
|
||||||
@@ -1476,7 +1474,7 @@ public final class ProcessStats implements Parcelable {
|
|||||||
} else {
|
} else {
|
||||||
// Don't need rate limiting on it.
|
// Don't need rate limiting on it.
|
||||||
Slog.wtf(TAG, "Tracking association without process: " + act
|
Slog.wtf(TAG, "Tracking association without process: " + act
|
||||||
+ " in " + act.getAssociationState());
|
+ " in " + asc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1640,7 +1638,8 @@ public final class ProcessStats implements Parcelable {
|
|||||||
ALL_PROC_STATES, now);
|
ALL_PROC_STATES, now);
|
||||||
proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
|
proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
|
||||||
ALL_PROC_STATES, now);
|
ALL_PROC_STATES, now);
|
||||||
proc.dumpInternalLocked(pw, " ", dumpAll);
|
proc.dumpInternalLocked(pw, " ", reqPackage,
|
||||||
|
totalTime, now, dumpAll);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
|
ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
|
||||||
@@ -1696,7 +1695,8 @@ public final class ProcessStats implements Parcelable {
|
|||||||
}
|
}
|
||||||
final AssociationDumpContainer cont =
|
final AssociationDumpContainer cont =
|
||||||
new AssociationDumpContainer(asc);
|
new AssociationDumpContainer(asc);
|
||||||
cont.mSources = asc.createSortedAssociations(now, totalTime);
|
cont.mSources = AssociationState
|
||||||
|
.createSortedAssociations(now, totalTime, asc.mSources);
|
||||||
cont.mTotalTime = asc.getTotalDuration(now);
|
cont.mTotalTime = asc.getTotalDuration(now);
|
||||||
cont.mActiveTime = asc.getActiveDuration(now);
|
cont.mActiveTime = asc.getActiveDuration(now);
|
||||||
associations.add(cont);
|
associations.add(cont);
|
||||||
@@ -1777,7 +1777,7 @@ public final class ProcessStats implements Parcelable {
|
|||||||
proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
|
proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
|
||||||
ALL_PROC_STATES, now);
|
ALL_PROC_STATES, now);
|
||||||
proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now);
|
proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now);
|
||||||
proc.dumpInternalLocked(pw, " ", dumpAll);
|
proc.dumpInternalLocked(pw, " ", reqPackage, totalTime, now, dumpAll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pw.print(" Total procs: "); pw.print(numShownProcs);
|
pw.print(" Total procs: "); pw.print(numShownProcs);
|
||||||
@@ -1792,6 +1792,10 @@ public final class ProcessStats implements Parcelable {
|
|||||||
for (int i = 0; i < mTrackingAssociations.size(); i++) {
|
for (int i = 0; i < mTrackingAssociations.size(); i++) {
|
||||||
final AssociationState.SourceState src = mTrackingAssociations.get(i);
|
final AssociationState.SourceState src = mTrackingAssociations.get(i);
|
||||||
final AssociationState asc = src.getAssociationState();
|
final AssociationState asc = src.getAssociationState();
|
||||||
|
if (asc == null) {
|
||||||
|
Slog.wtf(TAG, src.toString() + " shouldn't be in the tracking list.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
pw.print(" #");
|
pw.print(" #");
|
||||||
pw.print(i);
|
pw.print(i);
|
||||||
pw.print(": ");
|
pw.print(": ");
|
||||||
@@ -2353,85 +2357,47 @@ public final class ProcessStats implements Parcelable {
|
|||||||
* @param fieldId The proto output field ID
|
* @param fieldId The proto output field ID
|
||||||
* @param now The timestamp when the dump was initiated.
|
* @param now The timestamp when the dump was initiated.
|
||||||
* @param procState The target process where its association states should be dumped.
|
* @param procState The target process where its association states should be dumped.
|
||||||
* @param proc2Pkg The map between process to packages running within it.
|
|
||||||
* @param uidToPkgMap The map between UID to packages with this UID
|
* @param uidToPkgMap The map between UID to packages with this UID
|
||||||
*/
|
*/
|
||||||
public void dumpFilteredAssociationStatesProtoForProc(ProtoOutputStream proto,
|
public void dumpFilteredAssociationStatesProtoForProc(ProtoOutputStream proto,
|
||||||
long fieldId, long now, ProcessState procState,
|
long fieldId, long now, ProcessState procState,
|
||||||
final ProcessMap<ArraySet<PackageState>> proc2Pkg,
|
|
||||||
final SparseArray<ArraySet<String>> uidToPkgMap) {
|
final SparseArray<ArraySet<String>> uidToPkgMap) {
|
||||||
if (procState.isMultiPackage() && procState.getCommonProcess() != procState) {
|
if (procState.isMultiPackage() && procState.getCommonProcess() != procState) {
|
||||||
// It's a per-package process state, don't bother to write into statsd
|
// It's a per-package process state, don't bother to write into statsd
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ArrayMap<SourceKey, long[]> assocVals = new ArrayMap<>();
|
final ArrayMap<SourceKey, SourceState> sources = procState.mCommonSources;
|
||||||
final String procName = procState.getName();
|
if (sources != null && !sources.isEmpty()) {
|
||||||
final int procUid = procState.getUid();
|
final IProcessStats procStatsService = IProcessStats.Stub.asInterface(
|
||||||
final long procVersion = procState.getVersion();
|
ServiceManager.getService(SERVICE_NAME));
|
||||||
final ArraySet<PackageState> packages = proc2Pkg.get(procName, procUid);
|
if (procStatsService != null) {
|
||||||
if (packages == null || packages.isEmpty()) {
|
try {
|
||||||
// Shouldn't happen
|
final long minimum = procStatsService.getMinAssociationDumpDuration();
|
||||||
return;
|
for (int i = sources.size() - 1; i >= 0; i--) {
|
||||||
}
|
final SourceState src = sources.valueAt(i);
|
||||||
for (int i = packages.size() - 1; i >= 0; i--) {
|
long duration = src.mDuration;
|
||||||
final PackageState pkgState = packages.valueAt(i);
|
if (src.mNesting > 0) {
|
||||||
final ArrayMap<String, AssociationState> associations = pkgState.mAssociations;
|
duration += now - src.mStartUptime;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
if (duration < minimum) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final SourceKey key = sources.keyAt(i);
|
||||||
|
final long token = proto.start(fieldId);
|
||||||
|
final int idx = uidToPkgMap.indexOfKey(key.mUid);
|
||||||
|
ProcessState.writeCompressedProcessName(proto,
|
||||||
|
ProcessStatsAssociationProto.ASSOC_PROCESS_NAME,
|
||||||
|
key.mProcess, key.mPackage,
|
||||||
|
idx >= 0 && uidToPkgMap.valueAt(idx).size() > 1);
|
||||||
|
proto.write(ProcessStatsAssociationProto.ASSOC_UID, key.mUid);
|
||||||
|
proto.write(ProcessStatsAssociationProto.TOTAL_COUNT, src.mCount);
|
||||||
|
proto.write(ProcessStatsAssociationProto.TOTAL_DURATION_SECS,
|
||||||
|
(int) (duration / 1000));
|
||||||
|
proto.end(token);
|
||||||
}
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// ignore.
|
||||||
}
|
}
|
||||||
} 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);
|
|
||||||
final int idx = uidToPkgMap.indexOfKey(key.mUid);
|
|
||||||
ProcessState.writeCompressedProcessName(proto,
|
|
||||||
ProcessStatsAssociationProto.ASSOC_PROCESS_NAME,
|
|
||||||
key.mProcess, key.mPackage,
|
|
||||||
idx >= 0 && uidToPkgMap.valueAt(idx).size() > 1);
|
|
||||||
proto.write(ProcessStatsAssociationProto.ASSOC_UID, key.mUid);
|
|
||||||
proto.write(ProcessStatsAssociationProto.TOTAL_COUNT, (int) vals[1]);
|
|
||||||
proto.write(ProcessStatsAssociationProto.TOTAL_DURATION_SECS,
|
|
||||||
(int) (vals[0] / 1000));
|
|
||||||
proto.end(token);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user