summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2018-07-09 09:09:05 -0700
committerDianne Hackborn <hackbod@google.com>2018-07-09 12:46:53 -0700
commit95031ef2e6a6a00681ade493b353f8d443cafc0c (patch)
tree0e0abdc385f2e75d01c831961071a23372534568
parentbad8de914ad0edcc3dcafe217cecb9bd98ca7f72 (diff)
Now track "active time" in procstats.
Associations now keep track of the time they are actively involved in impacting their target application. This is based on the procstate propagating through the association being the same as the procstate of its target process... so it may count as active when there is another reason for that process to be in the same state. To do this, we now maintain a set of "tracking associations" -- these are in-use associations that we know we need to be tracking to determine whether they are active. This list is built based on whether we at all consider an association during an oom_adj computation, and at the end of that walked to determine which of those associations are currently active. Also add tracking of associations through external provider references, with a tag name now needing to be passed through so we can mark up the reason for the external reference. Test: manual Bug: 110957691 Change-Id: I426a499834e20a9d7f2b439faf9cb398d9792fa2
-rw-r--r--cmds/content/src/com/android/commands/content/Content.java2
-rw-r--r--cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java2
-rw-r--r--core/java/android/app/IActivityManager.aidl2
-rw-r--r--core/java/com/android/internal/app/procstats/AssociationState.java233
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessState.java6
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessStats.java123
-rw-r--r--core/java/com/android/internal/app/procstats/ServiceState.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java62
-rw-r--r--services/core/java/com/android/server/am/ConnectionRecord.java13
-rw-r--r--services/core/java/com/android/server/am/ContentProviderConnection.java13
-rw-r--r--services/core/java/com/android/server/am/ContentProviderRecord.java67
-rw-r--r--services/core/java/com/android/server/am/ProcessStatsService.java6
12 files changed, 445 insertions, 86 deletions
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 6e0bd3a81d84..36e51b9703c9 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -462,7 +462,7 @@ public class Content {
IBinder token = new Binder();
try {
ContentProviderHolder holder = activityManager.getContentProviderExternal(
- providerName, mUserId, token);
+ providerName, mUserId, token, "*cmd*");
if (holder == null) {
throw new IllegalStateException("Could not find provider: " + providerName);
}
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
index 653851546d01..950a258d123d 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
@@ -62,7 +62,7 @@ public class ShellUiAutomatorBridge extends UiAutomatorBridge {
IBinder token = new Binder();
try {
ContentProviderHolder holder = activityManager.getContentProviderExternal(
- providerName, UserHandle.USER_SYSTEM, token);
+ providerName, UserHandle.USER_SYSTEM, token, "*uiautomator*");
if (holder == null) {
throw new IllegalStateException("Could not find provider: " + providerName);
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index f9c39165b2c8..19d7c83818f6 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -268,7 +268,7 @@ interface IActivityManager {
void showBootMessage(in CharSequence msg, boolean always);
void killAllBackgroundProcesses();
ContentProviderHolder getContentProviderExternal(in String name, int userId,
- in IBinder token);
+ in IBinder token, String tag);
void removeContentProviderExternal(in String name, in IBinder token);
// Get memory information about the calling process.
void getMyMemoryState(out ActivityManager.RunningAppProcessInfo outInfo);
diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java
index e73ec1c40d19..e5d6556e1218 100644
--- a/core/java/com/android/internal/app/procstats/AssociationState.java
+++ b/core/java/com/android/internal/app/procstats/AssociationState.java
@@ -21,37 +21,143 @@ import android.os.Parcel;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.Slog;
import android.util.TimeUtils;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Objects;
public final class AssociationState {
private static final String TAG = "ProcessStats";
private static final boolean DEBUG = false;
- private final String mPackage;
+ private final ProcessStats mProcessStats;
+ private final ProcessStats.PackageState mPackageState;
private final String mProcessName;
private final String mName;
private final DurationsTable mDurations;
public final class SourceState {
+ final SourceKey mKey;
+ int mProcStateSeq = -1;
+ int mProcState = ProcessStats.STATE_NOTHING;
+ boolean mInTrackingList;
+ int mNesting;
+ int mCount;
+ long mStartUptime;
+ long mDuration;
+ long mTrackingUptime;
+ int mActiveCount;
+ long mActiveStartUptime;
+ long mActiveDuration;
+
+ SourceState(SourceKey key) {
+ mKey = key;
+ }
+
+ public AssociationState getAssociationState() {
+ return AssociationState.this;
+ }
+
+ public String getProcessName() {
+ return mKey.mProcess;
+ }
+
+ public int getUid() {
+ return mKey.mUid;
+ }
+
+ public void trackProcState(int procState, int seq, long now) {
+ procState = ProcessState.PROCESS_STATE_TO_STATE[procState];
+ if (seq != mProcStateSeq) {
+ mProcStateSeq = seq;
+ mProcState = procState;
+ } else if (procState < mProcState) {
+ mProcState = procState;
+ }
+ if (procState < ProcessStats.STATE_HOME) {
+ if (!mInTrackingList) {
+ mInTrackingList = true;
+ mTrackingUptime = now;
+ mProcessStats.mTrackingAssociations.add(this);
+ }
+ } else {
+ stopTracking(now);
+ }
+ }
+
public void stop() {
mNesting--;
if (mNesting == 0) {
- mDuration += SystemClock.uptimeMillis() - mStartTime;
+ mDuration += SystemClock.uptimeMillis() - mStartUptime;
mNumActive--;
+ stopTracking(SystemClock.uptimeMillis());
}
}
- int mNesting;
- int mCount;
- long mStartTime;
- long mDuration;
+ void startActive(long now) {
+ if (mInTrackingList) {
+ if (mActiveStartUptime == 0) {
+ mActiveStartUptime = now;
+ mActiveCount++;
+ }
+ } else {
+ Slog.wtf(TAG, "startActive while not tracking: " + this);
+ }
+ }
+
+ void stopActive(long now) {
+ if (mActiveStartUptime != 0) {
+ if (!mInTrackingList) {
+ Slog.wtf(TAG, "stopActive while not tracking: " + this);
+ }
+ mActiveDuration += now - mActiveStartUptime;
+ mActiveStartUptime = 0;
+ }
+ }
+
+ void stopTracking(long now) {
+ stopActive(now);
+ if (mInTrackingList) {
+ mInTrackingList = false;
+ // Do a manual search for where to remove, since these objects will typically
+ // be towards the end of the array.
+ final ArrayList<SourceState> list = mProcessStats.mTrackingAssociations;
+ for (int i = list.size() - 1; i >= 0; i--) {
+ if (list.get(i) == this) {
+ list.remove(i);
+ return;
+ }
+ }
+ Slog.wtf(TAG, "Stop tracking didn't find in tracking list: " + this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(64);
+ sb.append("SourceState{").append(Integer.toHexString(System.identityHashCode(this)))
+ .append(" ").append(mKey.mProcess).append("/").append(mKey.mUid);
+ if (mProcState != ProcessStats.STATE_NOTHING) {
+ sb.append(" ").append(DumpUtils.STATE_NAMES[mProcState]).append(" #")
+ .append(mProcStateSeq);
+ }
+ sb.append("}");
+ return sb.toString();
+ }
}
- final static class SourceKey {
+ private final static class SourceKey {
+ /**
+ * UID, consider this final. Not final just to avoid a temporary object during lookup.
+ */
int mUid;
+
+ /**
+ * Process name, consider this final. Not final just to avoid a temporary object during
+ * lookup.
+ */
String mProcess;
SourceKey(int uid, String process) {
@@ -82,7 +188,6 @@ public final class AssociationState {
sb.append('}');
return sb.toString();
}
-
}
/**
@@ -92,18 +197,26 @@ public final class AssociationState {
private final SourceKey mTmpSourceKey = new SourceKey(0, null);
+ private ProcessState mProc;
+
private int mNumActive;
- public AssociationState(ProcessStats processStats, String pkg, String name,
- String processName) {
- mPackage = pkg;
+ public AssociationState(ProcessStats processStats, ProcessStats.PackageState packageState,
+ String name, String processName, ProcessState proc) {
+ mProcessStats = processStats;
+ mPackageState = packageState;
mName = name;
mProcessName = processName;
mDurations = new DurationsTable(processStats.mTableData);
+ mProc = proc;
+ }
+
+ public int getUid() {
+ return mPackageState.mUid;
}
public String getPackage() {
- return mPackage;
+ return mPackageState.mPackageName;
}
public String getProcessName() {
@@ -114,18 +227,27 @@ public final class AssociationState {
return mName;
}
+ public ProcessState getProcess() {
+ return mProc;
+ }
+
+ public void setProcess(ProcessState proc) {
+ mProc = proc;
+ }
+
public SourceState startSource(int uid, String processName) {
mTmpSourceKey.mUid = uid;
mTmpSourceKey.mProcess = processName;
SourceState src = mSources.get(mTmpSourceKey);
if (src == null) {
- src = new SourceState();
- mSources.put(new SourceKey(uid, processName), src);
+ SourceKey key = new SourceKey(uid, processName);
+ src = new SourceState(key);
+ mSources.put(key, src);
}
src.mNesting++;
if (src.mNesting == 1) {
src.mCount++;
- src.mStartTime = SystemClock.uptimeMillis();
+ src.mStartUptime = SystemClock.uptimeMillis();
mNumActive++;
}
return src;
@@ -138,11 +260,13 @@ public final class AssociationState {
final SourceState otherSrc = other.mSources.valueAt(isrc);
SourceState mySrc = mSources.get(key);
if (mySrc == null) {
- mySrc = new SourceState();
+ mySrc = new SourceState(key);
mSources.put(key, mySrc);
}
mySrc.mCount += otherSrc.mCount;
mySrc.mDuration += otherSrc.mDuration;
+ mySrc.mActiveCount += otherSrc.mActiveCount;
+ mySrc.mActiveDuration += otherSrc.mActiveDuration;
}
}
@@ -160,8 +284,15 @@ public final class AssociationState {
SourceState src = mSources.valueAt(isrc);
if (src.mNesting > 0) {
src.mCount = 1;
- src.mStartTime = now;
+ src.mStartUptime = now;
src.mDuration = 0;
+ if (src.mActiveStartUptime > 0) {
+ src.mActiveCount = 1;
+ src.mActiveStartUptime = now;
+ } else {
+ src.mActiveCount = 0;
+ }
+ src.mActiveDuration = 0;
} else {
mSources.removeAt(isrc);
}
@@ -169,7 +300,7 @@ public final class AssociationState {
}
}
- public void writeToParcel(ProcessStats stats, Parcel out, long now) {
+ public void writeToParcel(ProcessStats stats, Parcel out, long nowUptime) {
mDurations.writeToParcel(out);
final int NSRC = mSources.size();
out.writeInt(NSRC);
@@ -180,9 +311,15 @@ public final class AssociationState {
stats.writeCommonString(out, key.mProcess);
out.writeInt(src.mCount);
out.writeLong(src.mDuration);
+ out.writeInt(src.mActiveCount);
+ out.writeLong(src.mActiveDuration);
}
}
+ /**
+ * Returns non-null if all else fine, else a String that describes the error that
+ * caused it to fail.
+ */
public String readFromParcel(ProcessStats stats, Parcel in, int parcelVersion) {
if (!mDurations.readFromParcel(in)) {
return "Duration table corrupt";
@@ -195,21 +332,27 @@ public final class AssociationState {
final int uid = in.readInt();
final String procName = stats.readCommonString(in, parcelVersion);
final SourceKey key = new SourceKey(uid, procName);
- final SourceState src = new SourceState();
+ final SourceState src = new SourceState(key);
src.mCount = in.readInt();
src.mDuration = in.readLong();
+ src.mActiveCount = in.readInt();
+ src.mActiveDuration = in.readLong();
mSources.put(key, src);
}
return null;
}
- public void commitStateTime(long now) {
+ public void commitStateTime(long nowUptime) {
if (isInUse()) {
for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) {
SourceState src = mSources.valueAt(isrc);
if (src.mNesting > 0) {
- src.mDuration += now - src.mStartTime;
- src.mStartTime = now;
+ src.mDuration += nowUptime - src.mStartUptime;
+ src.mStartUptime = nowUptime;
+ }
+ if (src.mActiveStartUptime > 0) {
+ src.mActiveDuration += nowUptime - src.mActiveStartUptime;
+ src.mActiveStartUptime = nowUptime;
}
}
}
@@ -237,7 +380,7 @@ public final class AssociationState {
pw.print(src.mCount);
long duration = src.mDuration;
if (src.mNesting > 0) {
- duration += now - src.mStartTime;
+ duration += now - src.mStartUptime;
}
if (dumpAll) {
pw.print(" / Duration ");
@@ -248,9 +391,37 @@ public final class AssociationState {
}
DumpUtils.printPercent(pw, (double)duration/(double)totalTime);
if (src.mNesting > 0) {
- pw.print(" (running)");
+ pw.print(" (running");
+ if (src.mProcState != ProcessStats.STATE_NOTHING) {
+ pw.print(" / ");
+ pw.print(DumpUtils.STATE_NAMES[src.mProcState]);
+ pw.print(" #");
+ pw.print(src.mProcStateSeq);
+ }
+ pw.print(")");
}
pw.println();
+ if (src.mActiveCount > 0) {
+ pw.print(prefixInner);
+ pw.print(" Active count ");
+ pw.print(src.mActiveCount);
+ duration = src.mActiveDuration;
+ if (src.mActiveStartUptime > 0) {
+ duration += now - src.mActiveStartUptime;
+ }
+ if (dumpAll) {
+ pw.print(" / Duration ");
+ TimeUtils.formatDuration(duration, pw);
+ pw.print(" / ");
+ } else {
+ pw.print(" / time ");
+ }
+ DumpUtils.printPercent(pw, (double)duration/(double)totalTime);
+ if (src.mActiveStartUptime > 0) {
+ pw.print(" (running)");
+ }
+ pw.println();
+ }
}
}
@@ -277,7 +448,15 @@ public final class AssociationState {
pw.print(src.mCount);
long duration = src.mDuration;
if (src.mNesting > 0) {
- duration += now - src.mStartTime;
+ duration += now - src.mStartUptime;
+ }
+ pw.print(",");
+ pw.print(duration);
+ pw.print(",");
+ pw.print(src.mActiveCount);
+ duration = src.mActiveDuration;
+ if (src.mActiveStartUptime > 0) {
+ duration += now - src.mActiveStartUptime;
}
pw.print(",");
pw.print(duration);
@@ -287,7 +466,7 @@ public final class AssociationState {
public String toString() {
return "AssociationState{" + Integer.toHexString(System.identityHashCode(this))
- + " " + mName + " pkg=" + mPackage + " proc="
- + Integer.toHexString(System.identityHashCode(this)) + "}";
+ + " " + mName + " pkg=" + mPackageState.mPackageName + " proc="
+ + Integer.toHexString(System.identityHashCode(mProc)) + "}";
}
}
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 5a08f62f218b..dbf7c93dadd2 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -71,7 +71,7 @@ public final class ProcessState {
private static final boolean DEBUG_PARCEL = false;
// Map from process states to the states we track.
- private static final int[] PROCESS_STATE_TO_STATE = new int[] {
+ static final int[] PROCESS_STATE_TO_STATE = new int[] {
STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT
STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
STATE_TOP, // ActivityManager.PROCESS_STATE_TOP
@@ -378,6 +378,10 @@ public final class ProcessState {
}
}
+ public int getState() {
+ return mCurState;
+ }
+
public void commitStateTime(long now) {
if (mCurState != STATE_NOTHING) {
long dur = now - mStartTime;
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 1f871d9f92b8..3cafa5e5ec20 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -16,6 +16,7 @@
package com.android.internal.app.procstats;
+import android.content.ComponentName;
import android.os.Debug;
import android.os.Parcel;
import android.os.Parcelable;
@@ -157,7 +158,7 @@ public final class ProcessStats implements Parcelable {
};
// Current version of the parcel format.
- private static final int PARCEL_VERSION = 31;
+ private static final int PARCEL_VERSION = 32;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0x50535454;
@@ -168,6 +169,8 @@ public final class ProcessStats implements Parcelable {
public final ProcessMap<LongSparseArray<PackageState>> mPackages = new ProcessMap<>();
public final ProcessMap<ProcessState> mProcesses = new ProcessMap<>();
+ public final ArrayList<AssociationState.SourceState> mTrackingAssociations = new ArrayList<>();
+
public final long[] mMemFactorDurations = new long[ADJ_COUNT];
public int mMemFactor = STATE_NOTHING;
public long mStartTime;
@@ -1203,8 +1206,8 @@ public final class ProcessStats implements Parcelable {
AssociationState asc = hadData
? pkgState.mAssociations.get(associationName) : null;
if (asc == null) {
- asc = new AssociationState(this, pkgName, associationName,
- processName);
+ asc = new AssociationState(this, pkgState, associationName,
+ processName, null);
}
String errorMsg = asc.readFromParcel(this, in, version);
if (errorMsg != null) {
@@ -1308,6 +1311,17 @@ public final class ProcessStats implements Parcelable {
Slog.d(TAG, "GETPROC leaving proc of " + ss);
}
}
+ // Also update active associations.
+ for (int i=commonPkgState.mAssociations.size()-1; i>=0; i--) {
+ AssociationState as = commonPkgState.mAssociations.valueAt(i);
+ if (as.getProcess() == commonProc) {
+ if (DEBUG) Slog.d(TAG, "GETPROC switching association to cloned: "
+ + as);
+ as.setProcess(cloned);
+ } else if (DEBUG) {
+ Slog.d(TAG, "GETPROC leaving proc of " + as);
+ }
+ }
} else {
Slog.w(TAG, "Cloning proc state: no package state " + commonProc.getPackage()
+ "/" + pkgState.mUid + " for proc " + commonProc.getName());
@@ -1356,12 +1370,41 @@ public final class ProcessStats implements Parcelable {
}
final ProcessState procs = processName != null
? getProcessStateLocked(packageName, uid, vers, processName) : null;
- as = new AssociationState(this, packageName, className, processName);
+ as = new AssociationState(this, pkgs, className, processName, procs);
pkgs.mAssociations.put(className, as);
if (DEBUG) Slog.d(TAG, "GETASC: creating " + as + " in " + procs);
return as;
}
+ public void updateTrackingAssociationsLocked(int curSeq, long now) {
+ final int NUM = mTrackingAssociations.size();
+ for (int i = NUM - 1; i >= 0; i--) {
+ final AssociationState.SourceState act = mTrackingAssociations.get(i);
+ if (act.mProcStateSeq != curSeq) {
+ act.mInTrackingList = false;
+ act.mProcState = STATE_NOTHING;
+ mTrackingAssociations.remove(i);
+ } else {
+ final ProcessState proc = act.getAssociationState().getProcess();
+ if (proc != null) {
+ if (act.mProcState == proc.getState()) {
+ act.startActive(now);
+ } else {
+ act.stopActive(now);
+ if (act.mProcState < proc.getState()) {
+ Slog.w(TAG, "Tracking association " + act + " whose proc state "
+ + act.mProcState + " is better than process " + proc
+ + " proc state " + proc.getState());
+ }
+ }
+ } else {
+ Slog.wtf(TAG, "Tracking association without process: " + act
+ + " in " + act.getAssociationState());
+ }
+ }
+ }
+ }
+
public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
boolean dumpAll, boolean activeOnly) {
long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
@@ -1543,10 +1586,70 @@ public final class ProcessStats implements Parcelable {
proc.dumpInternalLocked(pw, " ", dumpAll);
}
}
+
if (dumpAll) {
- pw.println();
+ if (sepNeeded) {
+ pw.println();
+ }
+ sepNeeded = true;
pw.print(" Total procs: "); pw.print(numShownProcs);
pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+ if (mTrackingAssociations.size() > 0) {
+ pw.println();
+ pw.println("Tracking associations:");
+ for (int i = 0; i < mTrackingAssociations.size(); i++) {
+ final AssociationState.SourceState src = mTrackingAssociations.get(i);
+ final AssociationState asc = src.getAssociationState();
+ pw.print(" #");
+ pw.print(i);
+ pw.print(": ");
+ pw.print(asc.getProcessName());
+ pw.print("/");
+ UserHandle.formatUid(pw, asc.getUid());
+ pw.print(" <- ");
+ pw.print(src.getProcessName());
+ pw.print("/");
+ UserHandle.formatUid(pw, src.getUid());
+ pw.println(":");
+ pw.print(" Tracking for: ");
+ TimeUtils.formatDuration(now - src.mTrackingUptime, pw);
+ pw.println();
+ pw.print(" Component: ");
+ pw.print(new ComponentName(asc.getPackage(), asc.getName())
+ .flattenToShortString());
+ pw.println();
+ pw.print(" Proc state: ");
+ if (src.mProcState != ProcessStats.STATE_NOTHING) {
+ pw.print(DumpUtils.STATE_NAMES[src.mProcState]);
+ } else {
+ pw.print("--");
+ }
+ pw.print(" #");
+ pw.println(src.mProcStateSeq);
+ pw.print(" Process: ");
+ pw.println(asc.getProcess());
+ if (src.mActiveCount > 0) {
+ pw.print(" Active count ");
+ pw.print(src.mActiveCount);
+ long duration = src.mActiveDuration;
+ if (src.mActiveStartUptime > 0) {
+ duration += now - src.mActiveStartUptime;
+ }
+ if (dumpAll) {
+ pw.print(" / Duration ");
+ TimeUtils.formatDuration(duration, pw);
+ pw.print(" / ");
+ } else {
+ pw.print(" / time ");
+ }
+ DumpUtils.printPercent(pw, (double)duration/(double)totalTime);
+ if (src.mActiveStartUptime > 0) {
+ pw.print(" (running)");
+ }
+ pw.println();
+ }
+ }
+ }
}
if (sepNeeded) {
@@ -1985,15 +2088,19 @@ public final class ProcessStats implements Parcelable {
mVersionCode = versionCode;
}
- public AssociationState getAssociationStateLocked(String processName, String className) {
+ public AssociationState getAssociationStateLocked(ProcessState proc, String className) {
AssociationState as = mAssociations.get(className);
if (as != null) {
if (DEBUG) Slog.d(TAG, "GETASC: returning existing " + as);
+ if (proc != null) {
+ as.setProcess(proc);
+ }
return as;
}
- as = new AssociationState(mProcessStats, mPackageName, className, processName);
+ as = new AssociationState(mProcessStats, this, className, proc.getName(),
+ proc);
mAssociations.put(className, as);
- if (DEBUG) Slog.d(TAG, "GETASC: creating " + as + " in " + processName);
+ if (DEBUG) Slog.d(TAG, "GETASC: creating " + as + " in " + proc.getName());
return as;
}
}
diff --git a/core/java/com/android/internal/app/procstats/ServiceState.java b/core/java/com/android/internal/app/procstats/ServiceState.java
index 53ed5c0128d8..04e61e067f53 100644
--- a/core/java/com/android/internal/app/procstats/ServiceState.java
+++ b/core/java/com/android/internal/app/procstats/ServiceState.java
@@ -554,6 +554,6 @@ public final class ServiceState {
public String toString() {
return "ServiceState{" + Integer.toHexString(System.identityHashCode(this))
+ " " + mName + " pkg=" + mPackage + " proc="
- + Integer.toHexString(System.identityHashCode(this)) + "}";
+ + Integer.toHexString(System.identityHashCode(mProc)) + "}";
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5028fd59124f..a23060982547 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -86,7 +86,6 @@ import static android.os.Process.setThreadPriority;
import static android.os.Process.setThreadScheduler;
import static android.os.Process.startWebView;
import static android.os.Process.zygoteProcess;
-import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
import static android.provider.Settings.Global.DEBUG_APP;
import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
@@ -164,7 +163,6 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityManagerProto;
import android.app.ActivityOptions;
import android.app.ActivityThread;
-import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
@@ -206,7 +204,6 @@ import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.IContentProvider;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
@@ -262,7 +259,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.Process;
@@ -285,7 +281,6 @@ import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.provider.Downloads;
import android.provider.Settings;
-import android.service.voice.IVoiceInteractionSession;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.style.SuggestionSpan;
@@ -323,10 +318,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.DumpHeapActivity;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.SystemUserHomeActivity;
-import com.android.internal.app.procstats.AssociationState;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -364,21 +357,9 @@ import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.ThreadPriorityBooster;
import com.android.server.Watchdog;
-import com.android.server.am.ActivityManagerServiceDumpActivitiesProto;
-import com.android.server.am.ActivityManagerServiceDumpBroadcastsProto;
-import com.android.server.am.ActivityManagerServiceDumpProcessesProto;
import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
-import com.android.server.am.ActivityManagerServiceDumpServicesProto;
-import com.android.server.am.ActivityManagerServiceProto;
import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.am.GrantUriProto;
-import com.android.server.am.ImportanceTokenProto;
-import com.android.server.am.MemInfoDumpProto;
import com.android.server.am.MemoryStatUtil.MemoryStat;
-import com.android.server.am.NeededUriGrantsProto;
-import com.android.server.am.ProcessOomProto;
-import com.android.server.am.ProcessToGcProto;
-import com.android.server.am.StickyBroadcastProto;
import com.android.server.firewall.IntentFirewall;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.pm.Installer;
@@ -387,7 +368,6 @@ import com.android.server.pm.dex.DexManager;
import com.android.server.utils.PriorityDump;
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
-import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
import com.android.server.wm.WindowManagerService;
import org.xmlpull.v1.XmlPullParser;
@@ -9020,7 +9000,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
ContentProviderConnection incProviderCountLocked(ProcessRecord r,
- final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
+ final ContentProviderRecord cpr, IBinder externalProcessToken, int callingUid,
+ String callingTag, boolean stable) {
if (r != null) {
for (int i=0; i<r.conProviders.size(); i++) {
ContentProviderConnection conn = r.conProviders.get(i);
@@ -9055,7 +9036,7 @@ public class ActivityManagerService extends IActivityManager.Stub
cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
return conn;
}
- cpr.addExternalProcessHandleLocked(externalProcessToken);
+ cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
return null;
}
@@ -9132,7 +9113,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
- String name, IBinder token, boolean stable, int userId) {
+ String name, IBinder token, int callingUid, String callingTag, boolean stable,
+ int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
@@ -9225,7 +9207,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// In this case the provider instance already exists, so we can
// return it right away.
- conn = incProviderCountLocked(r, cpr, token, stable);
+ conn = incProviderCountLocked(r, cpr, token, callingUid, callingTag, stable);
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
// If this is a perceptible app accessing the provider,
@@ -9469,7 +9451,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
mProviderMap.putProviderByName(name, cpr);
- conn = incProviderCountLocked(r, cpr, token, stable);
+ conn = incProviderCountLocked(r, cpr, token, callingUid, callingTag, stable);
if (conn != null) {
conn.waiting = true;
}
@@ -9580,21 +9562,23 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
// with cross-user grant.
- return getContentProviderImpl(caller, name, null, stable, userId);
+ return getContentProviderImpl(caller, name, null, Binder.getCallingUid(), null, stable,
+ userId);
}
public ContentProviderHolder getContentProviderExternal(
- String name, int userId, IBinder token) {
+ String name, int userId, IBinder token, String tag) {
enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
"Do not have permission in call getContentProviderExternal()");
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "getContentProvider", null);
- return getContentProviderExternalUnchecked(name, token, userId);
+ return getContentProviderExternalUnchecked(name, token, Binder.getCallingUid(),
+ tag != null ? tag : "*external*", userId);
}
private ContentProviderHolder getContentProviderExternalUnchecked(String name,
- IBinder token, int userId) {
- return getContentProviderImpl(null, name, token, true, userId);
+ IBinder token, int callingUid, String callingTag, int userId) {
+ return getContentProviderImpl(null, name, token, callingUid, callingTag, true, userId);
}
/**
@@ -9986,7 +9970,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
ContentProviderHolder holder = null;
try {
- holder = getContentProviderExternalUnchecked(name, null, userId);
+ holder = getContentProviderExternalUnchecked(name, null, callingUid,
+ "*getmimetype*", userId);
if (holder != null) {
return holder.provider.getType(uri);
}
@@ -10201,7 +10186,8 @@ public class ActivityManagerService extends IActivityManager.Stub
final int userId = UserHandle.getCallingUserId();
final Uri uri = Uri.parse(uriString);
String name = uri.getAuthority();
- ContentProviderHolder cph = getContentProviderExternalUnchecked(name, null, userId);
+ ContentProviderHolder cph = getContentProviderExternalUnchecked(name, null,
+ Binder.getCallingUid(), "*opencontent*", userId);
ParcelFileDescriptor pfd = null;
if (cph != null) {
// We record the binder invoker's uid in thread-local storage before
@@ -19281,10 +19267,11 @@ public class ActivityManagerService extends IActivityManager.Stub
// all connected clients.
ConnectionRecord cr = clist.get(i);
if (cr.binding.client == app) {
- // Binding to ourself is not interesting.
+ // Binding to oneself is not interesting.
continue;
}
+ boolean trackedProcState = false;
if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
ProcessRecord client = cr.binding.client;
computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
@@ -19356,6 +19343,8 @@ public class ActivityManagerService extends IActivityManager.Stub
newAdj = ProcessList.PERSISTENT_SERVICE_ADJ;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
procState = ActivityManager.PROCESS_STATE_PERSISTENT;
+ cr.trackProcState(procState, mAdjSeq, now);
+ trackedProcState = true;
}
} else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
@@ -19441,6 +19430,9 @@ public class ActivityManagerService extends IActivityManager.Stub
ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
}
}
+ if (!trackedProcState) {
+ cr.trackProcState(clientProcState, mAdjSeq, now);
+ }
if (procState > clientProcState) {
procState = clientProcState;
if (adjType == null) {
@@ -19570,6 +19562,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
}
+ conn.trackProcState(clientProcState, mAdjSeq, now);
if (procState > clientProcState) {
procState = clientProcState;
}
@@ -20839,6 +20832,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
}
+
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (!app.killedByAm && app.thread != null) {
@@ -20902,6 +20896,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
+
incrementProcStateSeqAndNotifyAppsLocked();
mNumServiceProcs = mNewNumServiceProcs;
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index c348aeee8b86..2cea4faba613 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -106,7 +106,10 @@ final class ConnectionRecord {
}
public void startAssociationIfNeeded() {
- if (association == null) {
+ // If we don't already have an active association, create one... but only if this
+ // is an association between two different processes.
+ if (association == null && (binding.service.appInfo.uid != clientUid
+ || !binding.service.processName.equals(clientProcessName))) {
ProcessStats.ProcessStateHolder holder = binding.service.app != null
? binding.service.app.pkgList.get(binding.service.name.getPackageName()) : null;
if (holder == null) {
@@ -116,7 +119,7 @@ final class ConnectionRecord {
Slog.wtf(TAG_AM, "Inactive holder in referenced service "
+ binding.service.name.toShortString() + ": proc=" + binding.service.app);
} else {
- association = holder.pkg.getAssociationStateLocked(binding.service.processName,
+ association = holder.pkg.getAssociationStateLocked(holder.state,
binding.service.name.getClassName()).startSource(clientUid,
clientProcessName);
@@ -124,6 +127,12 @@ final class ConnectionRecord {
}
}
+ public void trackProcState(int procState, int seq, long now) {
+ if (association != null) {
+ association.trackProcState(procState, seq, now);
+ }
+ }
+
public void stopAssociation() {
if (association != null) {
association.stop();
diff --git a/services/core/java/com/android/server/am/ContentProviderConnection.java b/services/core/java/com/android/server/am/ContentProviderConnection.java
index 0320b10b9a7a..36d3f4f619de 100644
--- a/services/core/java/com/android/server/am/ContentProviderConnection.java
+++ b/services/core/java/com/android/server/am/ContentProviderConnection.java
@@ -53,7 +53,10 @@ public final class ContentProviderConnection extends Binder {
}
public void startAssociationIfNeeded() {
- if (association == null) {
+ // If we don't already have an active association, create one... but only if this
+ // is an association between two different processes.
+ if (association == null && (provider.appInfo.uid != client.uid
+ || !provider.info.processName.equals(client.processName))) {
ProcessStats.ProcessStateHolder holder = provider.proc != null
? provider.proc.pkgList.get(provider.name.getPackageName()) : null;
if (holder == null) {
@@ -63,13 +66,19 @@ public final class ContentProviderConnection extends Binder {
Slog.wtf(TAG_AM, "Inactive holder in referenced provider "
+ provider.name.toShortString() + ": proc=" + provider.proc);
} else {
- association = holder.pkg.getAssociationStateLocked(provider.info.processName,
+ association = holder.pkg.getAssociationStateLocked(holder.state,
provider.name.getClassName()).startSource(client.uid, client.processName);
}
}
}
+ public void trackProcState(int procState, int seq, long now) {
+ if (association != null) {
+ association.trackProcState(procState, seq, now);
+ }
+ }
+
public void stopAssociation() {
if (association != null) {
association.stop();
diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
index 07ae1aedc686..53783bebe7f1 100644
--- a/services/core/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/core/java/com/android/server/am/ContentProviderRecord.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+
import android.app.ContentProviderHolder;
import android.content.ComponentName;
import android.content.IContentProvider;
@@ -26,11 +28,14 @@ import android.os.IBinder.DeathRecipient;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Slog;
+import com.android.internal.app.procstats.AssociationState;
+import com.android.internal.app.procstats.ProcessStats;
+
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
final class ContentProviderRecord implements ComponentName.WithComponentName {
final ActivityManagerService service;
@@ -46,7 +51,7 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
= new ArrayList<ContentProviderConnection>();
//final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
// Handles for non-framework processes supported by this provider
- HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
+ ArrayMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
// Count for external process for which we have no handles.
int externalProcessNoHandleCount;
ProcessRecord proc; // if non-null, hosting process.
@@ -93,6 +98,16 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
conn.stopAssociation();
}
}
+ if (externalProcessTokenToHandle != null) {
+ for (int iext = externalProcessTokenToHandle.size() - 1; iext >= 0; iext--) {
+ final ExternalProcessHandle handle = externalProcessTokenToHandle.valueAt(iext);
+ if (proc != null) {
+ handle.startAssociationIfNeeded(this);
+ } else {
+ handle.stopAssociation();
+ }
+ }
+ }
}
public boolean canRunHere(ProcessRecord app) {
@@ -100,17 +115,18 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
&& uid == app.info.uid;
}
- public void addExternalProcessHandleLocked(IBinder token) {
+ public void addExternalProcessHandleLocked(IBinder token, int callingUid, String callingTag) {
if (token == null) {
externalProcessNoHandleCount++;
} else {
if (externalProcessTokenToHandle == null) {
- externalProcessTokenToHandle = new HashMap<IBinder, ExternalProcessHandle>();
+ externalProcessTokenToHandle = new ArrayMap<>();
}
ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
if (handle == null) {
- handle = new ExternalProcessHandle(token);
+ handle = new ExternalProcessHandle(token, callingUid, callingTag);
externalProcessTokenToHandle.put(token, handle);
+ handle.startAssociationIfNeeded(this);
}
handle.mAcquisitionCount++;
}
@@ -141,6 +157,7 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
private void removeExternalProcessHandleInternalLocked(IBinder token) {
ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
handle.unlinkFromOwnDeathLocked();
+ handle.stopAssociation();
externalProcessTokenToHandle.remove(token);
if (externalProcessTokenToHandle.size() == 0) {
externalProcessTokenToHandle = null;
@@ -246,11 +263,16 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
private class ExternalProcessHandle implements DeathRecipient {
private static final String LOG_TAG = "ExternalProcessHanldle";
- private final IBinder mToken;
- private int mAcquisitionCount;
+ final IBinder mToken;
+ final int mOwningUid;
+ final String mOwningProcessName;
+ int mAcquisitionCount;
+ AssociationState.SourceState mAssociation;
- public ExternalProcessHandle(IBinder token) {
+ public ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName) {
mToken = token;
+ mOwningUid = owningUid;
+ mOwningProcessName = owningProcessName;
try {
token.linkToDeath(this, 0);
} catch (RemoteException re) {
@@ -262,6 +284,35 @@ final class ContentProviderRecord implements ComponentName.WithComponentName {
mToken.unlinkToDeath(this, 0);
}
+ public void startAssociationIfNeeded(ContentProviderRecord provider) {
+ // If we don't already have an active association, create one... but only if this
+ // is an association between two different processes.
+ if (mAssociation == null && (provider.appInfo.uid != mOwningUid
+ || !provider.info.processName.equals(mOwningProcessName))) {
+ ProcessStats.ProcessStateHolder holder = provider.proc != null
+ ? provider.proc.pkgList.get(provider.name.getPackageName()) : null;
+ if (holder == null) {
+ Slog.wtf(TAG_AM, "No package in referenced provider "
+ + provider.name.toShortString() + ": proc=" + provider.proc);
+ } else if (holder.pkg == null) {
+ Slog.wtf(TAG_AM, "Inactive holder in referenced provider "
+ + provider.name.toShortString() + ": proc=" + provider.proc);
+ } else {
+ mAssociation = holder.pkg.getAssociationStateLocked(holder.state,
+ provider.name.getClassName()).startSource(mOwningUid,
+ mOwningProcessName);
+
+ }
+ }
+ }
+
+ public void stopAssociation() {
+ if (mAssociation != null) {
+ mAssociation.stop();
+ mAssociation = null;
+ }
+ }
+
@Override
public void binderDied() {
synchronized (service) {
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index e1bc1bccdb14..f0bd8fa31478 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -32,7 +32,6 @@ import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.procstats.AssociationState;
import com.android.internal.app.procstats.DumpUtils;
import com.android.internal.app.procstats.IProcessStats;
import com.android.internal.app.procstats.ProcessState;
@@ -194,6 +193,11 @@ public final class ProcessStatsService extends IProcessStats.Stub {
}
@GuardedBy("mAm")
+ public void updateTrackingAssociationsLocked(int curSeq, long now) {
+ mProcessStats.updateTrackingAssociationsLocked(curSeq, now);
+ }
+
+ @GuardedBy("mAm")
public boolean shouldWriteNowLocked(long now) {
if (now > (mLastWriteTime+WRITE_PERIOD)) {
if (SystemClock.elapsedRealtime()