diff options
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() |