}
}
- public void getMemoryInfo(Debug.MemoryInfo outInfo) {
- Debug.getMemoryInfo(outInfo);
- }
-
public void dispatchPackageBroadcast(int cmd, String[] packages) {
queueOrSendMessage(H.DISPATCH_PACKAGE_BROADCAST, packages, cmd);
}
}
@Override
- public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin,
+ public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
boolean dumpInfo, boolean dumpDalvik, String[] args) {
FileOutputStream fout = new FileOutputStream(fd);
PrintWriter pw = new FastPrintWriter(fout);
try {
- return dumpMemInfo(pw, checkin, dumpInfo, dumpDalvik);
+ dumpMemInfo(pw, mem, checkin, dumpInfo, dumpDalvik);
} finally {
pw.flush();
}
}
- private Debug.MemoryInfo dumpMemInfo(PrintWriter pw, boolean checkin, boolean dumpInfo,
- boolean dumpDalvik) {
+ private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
+ boolean dumpInfo, boolean dumpDalvik) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
- Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
- Debug.getMemoryInfo(memInfo);
-
- if (!dumpInfo) {
- return memInfo;
- }
-
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.totalMemory() / 1024;
}
pw.println();
- return memInfo;
+ return;
}
// otherwise, show human-readable format
pw.println(" Asset Allocations");
pw.print(assetAlloc);
}
-
- return memInfo;
}
@Override
return true;
}
- case GET_MEMORY_INFO_TRANSACTION:
- {
- data.enforceInterface(IApplicationThread.descriptor);
- Debug.MemoryInfo mi = new Debug.MemoryInfo();
- getMemoryInfo(mi);
- reply.writeNoException();
- mi.writeToParcel(reply, 0);
- return true;
- }
-
case DISPATCH_PACKAGE_BROADCAST_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
{
data.enforceInterface(IApplicationThread.descriptor);
ParcelFileDescriptor fd = data.readFileDescriptor();
+ Debug.MemoryInfo mi = Debug.MemoryInfo.CREATOR.createFromParcel(data);
boolean checkin = data.readInt() != 0;
boolean dumpInfo = data.readInt() != 0;
boolean dumpDalvik = data.readInt() != 0;
String[] args = data.readStringArray();
- Debug.MemoryInfo mi = null;
if (fd != null) {
try {
- mi = dumpMemInfo(fd.getFileDescriptor(), checkin, dumpInfo, dumpDalvik, args);
+ dumpMemInfo(fd.getFileDescriptor(), mi, checkin, dumpInfo, dumpDalvik, args);
} finally {
try {
fd.close();
}
}
reply.writeNoException();
- mi.writeToParcel(reply, 0);
return true;
}
data.recycle();
}
- public void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IApplicationThread.descriptor);
- mRemote.transact(GET_MEMORY_INFO_TRANSACTION, data, reply, 0);
- reply.readException();
- outInfo.readFromParcel(reply);
- data.recycle();
- reply.recycle();
- }
-
public void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
IBinder.FLAG_ONEWAY);
}
- public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean dumpInfo,
- boolean dumpDalvik, String[] args) throws RemoteException {
+ public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
+ boolean dumpInfo, boolean dumpDalvik, String[] args) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeFileDescriptor(fd);
+ mem.writeToParcel(data, 0);
data.writeInt(checkin ? 1 : 0);
data.writeInt(dumpInfo ? 1 : 0);
data.writeInt(dumpDalvik ? 1 : 0);
data.writeStringArray(args);
mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
reply.readException();
- Debug.MemoryInfo info = new Debug.MemoryInfo();
- info.readFromParcel(reply);
data.recycle();
reply.recycle();
- return info;
}
public void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException {
void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
throws RemoteException;
void setSchedulingGroup(int group) throws RemoteException;
- void getMemoryInfo(Debug.MemoryInfo outInfo) throws RemoteException;
static final int PACKAGE_REMOVED = 0;
static final int EXTERNAL_STORAGE_UNAVAILABLE = 1;
void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException;
void setCoreSettings(Bundle coreSettings) throws RemoteException;
void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
void scheduleTrimMemory(int level) throws RemoteException;
- Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, boolean checkin, boolean dumpInfo,
+ void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin, boolean dumpInfo,
boolean dumpDalvik, String[] args) throws RemoteException;
void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException;
int SET_SCHEDULING_GROUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+28;
int SCHEDULE_CREATE_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
int SCHEDULE_DESTROY_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
- int GET_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
+
int SCHEDULE_SUICIDE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
int SCHEDULE_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+34;
static final String CSV_SEP = "\t";
// Current version of the parcel format.
- private static final int PARCEL_VERSION = 12;
+ private static final int PARCEL_VERSION = 13;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0x50535453;
pw.print(prefix); pw.print("Killed for excessive CPU use: ");
pw.print(proc.mNumExcessiveCpu); pw.println(" times");
}
+ if (proc.mNumCachedKill != 0) {
+ pw.print(prefix); pw.print("Killed from cached state: ");
+ pw.print(proc.mNumCachedKill); pw.print(" times from pss ");
+ printSizeValue(pw, proc.mMinCachedKillPss * 1024); pw.print("-");
+ printSizeValue(pw, proc.mAvgCachedKillPss * 1024); pw.print("-");
+ printSizeValue(pw, proc.mMaxCachedKillPss * 1024); pw.println();
+ }
}
static void dumpStateHeadersCsv(PrintWriter pw, String sep, int[] screenStates,
dumpAllProcessPssCheckin(pw, proc);
pw.println();
}
- if (proc.mNumExcessiveWake > 0 || proc.mNumExcessiveCpu > 0) {
+ if (proc.mNumExcessiveWake > 0 || proc.mNumExcessiveCpu > 0
+ || proc.mNumCachedKill > 0) {
pw.print("pkgkills,");
pw.print(pkgName);
pw.print(",");
pw.print(proc.mNumExcessiveWake);
pw.print(",");
pw.print(proc.mNumExcessiveCpu);
+ pw.print(",");
+ pw.print(proc.mNumCachedKill);
+ pw.print(",");
+ pw.print(proc.mMinCachedKillPss);
+ pw.print(":");
+ pw.print(proc.mAvgCachedKillPss);
+ pw.print(":");
+ pw.print(proc.mMaxCachedKillPss);
pw.println();
}
}
dumpAllProcessPssCheckin(pw, procState);
pw.println();
}
- if (procState.mNumExcessiveWake > 0 || procState.mNumExcessiveCpu > 0) {
+ if (procState.mNumExcessiveWake > 0 || procState.mNumExcessiveCpu > 0
+ || procState.mNumCachedKill > 0) {
pw.print("kills,");
pw.print(procName);
pw.print(",");
pw.print(procState.mNumExcessiveWake);
pw.print(",");
pw.print(procState.mNumExcessiveCpu);
+ pw.print(",");
+ pw.print(procState.mNumCachedKill);
+ pw.print(",");
+ pw.print(procState.mMinCachedKillPss);
+ pw.print(":");
+ pw.print(procState.mAvgCachedKillPss);
+ pw.print(":");
+ pw.print(procState.mMaxCachedKillPss);
pw.println();
}
}
int mNumExcessiveWake;
int mNumExcessiveCpu;
+ int mNumCachedKill;
+ long mMinCachedKillPss;
+ long mAvgCachedKillPss;
+ long mMaxCachedKillPss;
+
boolean mMultiPackage;
boolean mDead;
}
pnew.mNumExcessiveWake = mNumExcessiveWake;
pnew.mNumExcessiveCpu = mNumExcessiveCpu;
+ pnew.mNumCachedKill = mNumCachedKill;
+ pnew.mMinCachedKillPss = mMinCachedKillPss;
+ pnew.mAvgCachedKillPss = mAvgCachedKillPss;
+ pnew.mMaxCachedKillPss = mMaxCachedKillPss;
pnew.mActive = mActive;
pnew.mNumStartedServices = mNumStartedServices;
return pnew;
}
mNumExcessiveWake += other.mNumExcessiveWake;
mNumExcessiveCpu += other.mNumExcessiveCpu;
+ if (other.mNumCachedKill > 0) {
+ addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
+ other.mAvgCachedKillPss, other.mMaxCachedKillPss);
+ }
}
void resetSafely(long now) {
mPssTableSize = 0;
mNumExcessiveWake = 0;
mNumExcessiveCpu = 0;
+ mNumCachedKill = 0;
+ mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
}
void makeDead() {
}
out.writeInt(mNumExcessiveWake);
out.writeInt(mNumExcessiveCpu);
+ out.writeInt(mNumCachedKill);
+ if (mNumCachedKill > 0) {
+ out.writeLong(mMinCachedKillPss);
+ out.writeLong(mAvgCachedKillPss);
+ out.writeLong(mMaxCachedKillPss);
+ }
}
boolean readFromParcel(Parcel in, boolean fully) {
mPssTableSize = mPssTable != null ? mPssTable.length : 0;
mNumExcessiveWake = in.readInt();
mNumExcessiveCpu = in.readInt();
+ mNumCachedKill = in.readInt();
+ if (mNumCachedKill > 0) {
+ mMinCachedKillPss = in.readLong();
+ mAvgCachedKillPss = in.readLong();
+ mMaxCachedKillPss = in.readLong();
+ } else {
+ mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
+ }
return true;
}
}
}
+ private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
+ if (mNumCachedKill <= 0) {
+ mNumCachedKill = num;
+ mMinCachedKillPss = minPss;
+ mAvgCachedKillPss = avgPss;
+ mMaxCachedKillPss = maxPss;
+ } else {
+ if (minPss < mMinCachedKillPss) {
+ mMinCachedKillPss = minPss;
+ }
+ if (maxPss > mMaxCachedKillPss) {
+ mMaxCachedKillPss = maxPss;
+ }
+ mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
+ / (mNumCachedKill+num) );
+ mNumCachedKill += num;
+ }
+ }
+
+ public void reportCachedKill(ArrayMap<String, ProcessState> pkgList, long pss) {
+ ensureNotDead();
+ mCommonProcess.addCachedKill(1, pss, pss, pss);
+ if (!mCommonProcess.mMultiPackage) {
+ return;
+ }
+
+ for (int ip=pkgList.size()-1; ip>=0; ip--) {
+ pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
+ }
+ }
+
ProcessState pullFixedProc(String pkgName) {
if (mMultiPackage) {
// The array map is still pointing to a common process state
mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
new Intent(Intent.ACTION_TIME_TICK).addFlags(
- Intent.FLAG_RECEIVER_REGISTERED_ONLY), 0,
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND), 0,
UserHandle.ALL);
Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
final ServiceMap smap = getServiceMap(r.userId);
boolean addToStarting = false;
if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {
- ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid);
+ ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
// If this is not coming from a foreground caller, then we may want
// to delay the start if there are already other background services
if (r.isForeground) {
r.isForeground = false;
if (r.app != null) {
- mAm.updateLruProcessLocked(r.app, false);
+ mAm.updateLruProcessLocked(r.app, false, false);
updateServiceForegroundLocked(r.app, true);
}
}
ProcessRecord app;
if (!isolated) {
- app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);
- if (DEBUG_MU)
- Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);
+ app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
+ if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ + " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, mAm.mProcessStats);
// to be executed when the app comes up.
if (app == null) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
- "service", r.name, false, isolated)) == null) {
+ "service", r.name, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
- mAm.updateLruProcessLocked(app, true);
+ mAm.updateLruProcessLocked(app, true, false);
boolean created = false;
try {
final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>();
/**
+ * Where in mLruProcesses that the processes hosting activities start.
+ */
+ int mLruProcessActivityStart = 0;
+
+ /**
* List of processes that should gc as soon as things are idle.
*/
final ArrayList<ProcessRecord> mProcessesToGc = new ArrayList<ProcessRecord>();
int pid;
synchronized (ActivityManagerService.this) {
if (i >= mPendingPssProcesses.size()) {
- if (DEBUG_PSS) Slog.i(TAG, "Collected PSS of " + num + " of " + i
+ if (DEBUG_PSS) Slog.d(TAG, "Collected PSS of " + num + " of " + i
+ " processes in " + (SystemClock.uptimeMillis()-start) + "ms");
mPendingPssProcesses.clear();
return;
num++;
proc.lastPssTime = SystemClock.uptimeMillis();
proc.baseProcessTracker.addPss(pss, tmp[0], true);
+ if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
+ + ": " + pss + " lastPss=" + proc.lastPss
+ + " state=" + ProcessList.makeProcStateString(procState));
if (proc.initialIdlePss == 0) {
proc.initialIdlePss = pss;
}
proc.lastPss = pss;
+ if (procState >= ActivityManager.PROCESS_STATE_HOME) {
+ proc.lastCachedPss = pss;
+ }
}
}
}
synchronized (mSelf.mPidsSelfLocked) {
mSelf.mPidsSelfLocked.put(app.pid, app);
}
- mSelf.updateLruProcessLocked(app, true);
+ mSelf.updateLruProcessLocked(app, true, false);
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
mHandler.sendMessage(msg);
}
- private final void updateLruProcessInternalLocked(ProcessRecord app, int bestPos) {
- // put it on the LRU to keep track of when it should be exited.
- int lrui = mLruProcesses.indexOf(app);
- if (lrui >= 0) mLruProcesses.remove(lrui);
+ private final int updateLruProcessInternalLocked(ProcessRecord app, long now, int index) {
+ app.lastActivityTime = now;
- int i = mLruProcesses.size()-1;
- int skipTop = 0;
+ if (app.activities.size() > 0) {
+ // Don't want to touch dependent processes that are hosting activities.
+ return index;
+ }
- app.lruSeq = mLruSeq;
+ int lrui = mLruProcesses.lastIndexOf(app);
+ if (lrui < 0) {
+ throw new IllegalStateException("Adding dependent process " + app
+ + " not on LRU list!");
+ }
- // compute the new weight for this process.
- app.lastActivityTime = SystemClock.uptimeMillis();
- if (app.activities.size() > 0) {
- // If this process has activities, we more strongly want to keep
- // it around.
- app.lruWeight = app.lastActivityTime;
- } else if (app.pubProviders.size() > 0) {
- // If this process contains content providers, we want to keep
- // it a little more strongly.
- app.lruWeight = app.lastActivityTime - ProcessList.CONTENT_APP_IDLE_OFFSET;
- // Also don't let it kick out the first few "real" cached processes.
- skipTop = ProcessList.MIN_CACHED_APPS;
- } else {
- // If this process doesn't have activities, we less strongly
- // want to keep it around, and generally want to avoid getting
- // in front of any very recently used activities.
- app.lruWeight = app.lastActivityTime - ProcessList.EMPTY_APP_IDLE_OFFSET;
- // Also don't let it kick out the first few "real" cached processes.
- skipTop = ProcessList.MIN_CACHED_APPS;
- }
-
- while (i >= 0) {
- ProcessRecord p = mLruProcesses.get(i);
- // If this app shouldn't be in front of the first N background
- // apps, then skip over that many that are currently cached.
- if (skipTop > 0 && p.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
- skipTop--;
- }
- if (p.lruWeight <= app.lruWeight || i < bestPos) {
- mLruProcesses.add(i+1, app);
- break;
+ if (lrui >= mLruProcessActivityStart) {
+ // Don't want to touch dependent processes that are hosting activities.
+ return index;
+ }
+
+ mLruProcesses.remove(lrui);
+ if (index > 0) {
+ index--;
+ }
+ mLruProcesses.add(index, app);
+ return index;
+ }
+
+ final void removeLruProcessLocked(ProcessRecord app) {
+ int lrui = mLruProcesses.lastIndexOf(app);
+ if (lrui >= 0) {
+ if (lrui <= mLruProcessActivityStart) {
+ mLruProcessActivityStart--;
}
- i--;
+ mLruProcesses.remove(lrui);
+ }
+ }
+
+ final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj, boolean activityChange) {
+ final boolean hasActivity = app.activities.size() > 0;
+ if (!activityChange && hasActivity) {
+ // The process has activties, so we are only going to allow activity-based
+ // adjustments move it. It should be kept in the front of the list with other
+ // processes that have activities, and we don't want those to change their
+ // order except due to activity operations.
+ return;
+ }
+
+ mLruSeq++;
+ final long now = SystemClock.uptimeMillis();
+ app.lastActivityTime = now;
+
+ int lrui = mLruProcesses.lastIndexOf(app);
+
+ if (lrui >= 0) {
+ if (lrui < mLruProcessActivityStart) {
+ mLruProcessActivityStart--;
+ }
+ mLruProcesses.remove(lrui);
}
- if (i < 0) {
- mLruProcesses.add(0, app);
+
+ int nextIndex;
+ if (!hasActivity) {
+ // Process doesn't have activities, it goes to the top of the non-activity area.
+ mLruProcesses.add(mLruProcessActivityStart, app);
+ nextIndex = mLruProcessActivityStart-1;
+ mLruProcessActivityStart++;
+ } else {
+ // Process does have activities, put it at the very tipsy-top.
+ mLruProcesses.add(app);
+ nextIndex = mLruProcessActivityStart;
}
// If the app is currently using a content provider or service,
if (cr.binding != null && cr.binding.service != null
&& cr.binding.service.app != null
&& cr.binding.service.app.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cr.binding.service.app, i+1);
+ nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex);
}
}
for (int j=app.conProviders.size()-1; j>=0; j--) {
ContentProviderRecord cpr = app.conProviders.get(j).provider;
if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cpr.proc, i+1);
+ nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex);
}
}
- }
-
- final void updateLruProcessLocked(ProcessRecord app, boolean oomAdj) {
- mLruSeq++;
- updateLruProcessInternalLocked(app, 0);
//Slog.i(TAG, "Putting proc to front: " + app.processName);
if (oomAdj) {
}
}
- final ProcessRecord getProcessRecordLocked(
- String processName, int uid) {
+ final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
if (uid == Process.SYSTEM_UID) {
// The system gets to run in any process. If there are multiple
// processes with the same uid, just pick the first (this
// should never happen).
- SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
- processName);
+ SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
if (procs == null) return null;
final int N = procs.size();
for (int i = 0; i < N; i++) {
}
}
ProcessRecord proc = mProcessNames.get(processName, uid);
+ if (false && proc != null && !keepIfLarge
+ && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY
+ && proc.lastCachedPss >= 4000) {
+ // Turn this condition on to cause killing to happen regularly, for testing.
+ if (proc.baseProcessTracker != null) {
+ proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
+ }
+ killUnneededProcessLocked(proc, Long.toString(proc.lastCachedPss)
+ + "k from cached");
+ } else if (proc != null && !keepIfLarge && mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
+ && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
+ if (DEBUG_PSS) Slog.d(TAG, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
+ if (proc.lastCachedPss >= mProcessList.getCachedRestoreThreshold()) {
+ if (proc.baseProcessTracker != null) {
+ proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
+ }
+ killUnneededProcessLocked(proc, Long.toString(proc.lastCachedPss)
+ + "k from cached");
+ }
+ }
return proc;
}
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
- boolean isolated) {
+ boolean isolated, boolean keepIfLarge) {
ProcessRecord app;
if (!isolated) {
- app = getProcessRecordLocked(processName, info.uid);
+ app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
} else {
// If this is an isolated process, it can't re-use an existing process.
app = null;
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
- aInfo.applicationInfo.uid);
+ aInfo.applicationInfo.uid, true);
if (app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
mStackSupervisor.startHomeActivity(intent, aInfo);
boolean restarting, boolean allowRestart) {
cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
if (!restarting) {
- mLruProcesses.remove(app);
+ removeLruProcessLocked(app);
}
if (mProfileProc == app) {
// Only the system server can kill an application
if (callerUid == Process.SYSTEM_UID) {
synchronized (this) {
- ProcessRecord app = getProcessRecordLocked(processName, uid);
+ ProcessRecord app = getProcessRecordLocked(processName, uid, true);
if (app != null && app.thread != null) {
try {
app.thread.scheduleSuicide();
}
killUnneededProcessLocked(app, reason);
handleAppDiedLocked(app, true, allowRestart);
- mLruProcesses.remove(app);
+ removeLruProcessLocked(app);
if (app.persistent && !app.isolated) {
if (!callerWillRestart) {
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
- updateLruProcessLocked(app, false);
+ updateLruProcessLocked(app, false, false);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
// todo: Yikes! What should we do? For now we will try to
// make sure to count it as being accessed and thus
// back up on the LRU list. This is good because
// content providers are often expensive to start.
- updateLruProcessLocked(cpr.proc, false);
+ updateLruProcessLocked(cpr.proc, false, false);
}
}
ProcessRecord proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
- cpi.name), false, false);
+ cpi.name), false, false, false);
if (proc == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) {
ProcessRecord app;
if (!isolated) {
- app = getProcessRecordLocked(info.processName, info.uid);
+ app = getProcessRecordLocked(info.processName, info.uid, true);
} else {
app = null;
}
if (isolated) {
mIsolatedProcesses.put(app.uid, app);
}
- updateLruProcessLocked(app, true);
+ updateLruProcessLocked(app, true, false);
}
// This package really, really can not be stopped.
} else if (proc.setProcState < ActivityManager.PROCESS_STATE_HOME) {
proc.notCachedSinceIdle = true;
proc.initialIdlePss = 0;
+ proc.nextPssTime = ProcessList.computeNextPssTime(proc.curProcState, true,
+ mSleeping, now);
}
}
}
if (mLruProcesses.size() > 0) {
- boolean printed = dumpProcessOomList(pw, this, mLruProcesses, " ",
- "Proc", "PERS", false, dumpPackage, needSep,
- " Process LRU list (sorted by oom_adj):");
- if (printed) {
- needSep = true;
- printedAnything = true;
+ if (needSep) {
+ pw.println();
}
+ pw.print(" Process LRU list (sorted by oom_adj, "); pw.print(mLruProcesses.size());
+ pw.print(" total, non-activities at ");
+ pw.print(mLruProcesses.size()-mLruProcessActivityStart);
+ pw.println("):");
+ dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", false, dumpPackage);
+ needSep = true;
+ printedAnything = true;
}
if (dumpAll || dumpPackage != null) {
printOomLevel(pw, "CACHED_APP_MAX_ADJ", ProcessList.CACHED_APP_MAX_ADJ);
if (needSep) pw.println();
- needSep = true;
- pw.println(" Process OOM control:");
- dumpProcessOomList(pw, this, mLruProcesses, " ",
- "Proc", "PERS", true, null, false, null);
+ pw.print(" Process OOM control ("); pw.print(mLruProcesses.size());
+ pw.print(" total, non-activities at ");
+ pw.print(mLruProcesses.size()-mLruProcessActivityStart);
+ pw.println("):");
+ dumpProcessOomList(pw, this, mLruProcesses, " ", "Proc", "PERS", true, null);
needSep = true;
}
- needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, null);
+ dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll, null);
pw.println();
pw.println(" mHomeProcess: " + mHomeProcess);
private static final boolean dumpProcessOomList(PrintWriter pw,
ActivityManagerService service, List<ProcessRecord> origList,
String prefix, String normalLabel, String persistentLabel,
- boolean inclDetails, String dumpPackage, boolean needSep, String header) {
+ boolean inclDetails, String dumpPackage) {
ArrayList<Pair<ProcessRecord, Integer>> list
= new ArrayList<Pair<ProcessRecord, Integer>>(origList.size());
return false;
}
- if (header != null) {
- if (needSep) {
- pw.println();
- }
- pw.println(header);
- }
-
Comparator<Pair<ProcessRecord, Integer>> comparator
= new Comparator<Pair<ProcessRecord, Integer>>() {
@Override
pw.print(" set="); pw.println(r.setAdj);
pw.print(prefix);
pw.print(" ");
+ pw.print("state: cur="); pw.print(ProcessList.makeProcStateString(r.curProcState));
+ pw.print(" set="); pw.print(ProcessList.makeProcStateString(r.setProcState));
+ pw.print(" lastPss="); pw.print(r.lastPss);
+ pw.print(" lastCachedPss="); pw.println(r.lastCachedPss);
+ pw.print(prefix);
+ pw.print(" ");
pw.print("keeping="); pw.print(r.keeping);
pw.print(" cached="); pw.print(r.cached);
pw.print(" empty="); pw.print(r.empty);
if (!isCheckinRequest && dumpDetails) {
pw.println("\n** MEMINFO in pid " + pid + " [" + r.processName + "] **");
}
+ if (mi == null) {
+ mi = new Debug.MemoryInfo();
+ }
+ if (dumpDetails || (!brief && !oomOnly)) {
+ Debug.getMemoryInfo(pid, mi);
+ } else {
+ mi.dalvikPss = (int)Debug.getPss(pid, tmpLong);
+ mi.dalvikPrivateDirty = (int)tmpLong[0];
+ }
if (dumpDetails) {
try {
pw.flush();
- mi = null;
- mi = thread.dumpMemInfo(fd, isCheckinRequest, true, dumpDalvik, innerArgs);
+ thread.dumpMemInfo(fd, mi, isCheckinRequest, true, dumpDalvik, innerArgs);
} catch (RemoteException e) {
if (!isCheckinRequest) {
pw.println("Got RemoteException!");
pw.flush();
}
}
- } else {
- if (mi == null) {
- mi = new Debug.MemoryInfo();
- }
- if (!brief && !oomOnly) {
- Debug.getMemoryInfo(pid, mi);
- } else {
- mi.dalvikPss = (int)Debug.getPss(pid, tmpLong);
- mi.dalvikPrivateDirty = (int)tmpLong[0];
- }
}
final long myTotalPss = mi.getTotalPss();
private final void cleanUpApplicationRecordLocked(ProcessRecord app,
boolean restarting, boolean allowRestart, int index) {
if (index >= 0) {
- mLruProcesses.remove(index);
+ removeLruProcessLocked(app);
}
mProcessesToGc.remove(app);
: new ComponentName("android", "FullBackupAgent");
// startProcessLocked() returns existing proc's record if it's already running
ProcessRecord proc = startProcessLocked(app.processName, app,
- false, 0, "backup", hostingName, false, false);
+ false, 0, "backup", hostingName, false, false, false);
if (proc == null) {
Slog.e(TAG, "Unable to start backup agent process " + r);
return false;
}
if (app.setProcState < 0 || ProcessList.procStatesDifferForMem(app.curProcState,
app.setProcState)) {
- if (DEBUG_PSS) Slog.d(TAG, "Process state change from " + app.setProcState
- + " to " + app.curProcState + ": " + app);
app.lastStateTime = now;
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
mSleeping, now);
+ if (DEBUG_PSS) Slog.d(TAG, "Process state change from "
+ + ProcessList.makeProcStateString(app.setProcState) + " to "
+ + ProcessList.makeProcStateString(app.curProcState) + " next pss in "
+ + (app.nextPssTime-now) + ": " + app);
} else {
if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
&& now > (app.lastStateTime+ProcessList.PSS_MIN_TIME_FROM_STATE_CHANGE))) {
requestPssLocked(app, app.setProcState);
app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
mSleeping, now);
+ } else if (false && DEBUG_PSS) {
+ Slog.d(TAG, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
}
}
if (app.setProcState != app.curProcState) {
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
if (next.app != null && next.app.thread != null) {
// No reason to do full oom adj update here; we'll let that
// happen whenever it needs to later.
- mService.updateLruProcessLocked(next.app, false);
+ mService.updateLruProcessLocked(next.app, false, true);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
mResumedActivity = next;
next.task.touchActiveTime();
mService.addRecentTaskLocked(next.task);
- mService.updateLruProcessLocked(next.app, true);
+ mService.updateLruProcessLocked(next.app, true, true);
updateLRUListLocked(next);
// Have the window manager re-evaluate the orientation of
ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
}
if (r.app.activities.isEmpty()) {
- // No longer have activities, so update oom adj.
+ // No longer have activities, so update LRU list and oom adj.
+ mService.updateLruProcessLocked(r.app, false, false);
mService.updateOomAdjLocked();
}
}
if (idx < 0) {
app.activities.add(r);
}
- mService.updateLruProcessLocked(app, true);
+ mService.updateLruProcessLocked(app, true, true);
final ActivityStack stack = r.task.stack;
try {
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
- r.info.applicationInfo.uid);
+ r.info.applicationInfo.uid, true);
r.task.stack.setLaunchTime(r);
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
- "activity", r.intent.getComponent(), false, false);
+ "activity", r.intent.getComponent(), false, false, true);
}
final int startActivityLocked(IApplicationThread caller,
r.curApp = app;
app.curReceiver = r;
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
- mService.updateLruProcessLocked(app, true);
+ mService.updateLruProcessLocked(app, true, false);
// Tell the application to launch this receiver.
r.intent.setComponent(r.curComponent);
public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
final int state = r.state;
+ final ActivityInfo receiver = r.curReceiver;
r.state = BroadcastRecord.IDLE;
if (state == BroadcastRecord.IDLE) {
Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
&& r.queue.mOrderedBroadcasts.size() > 0
&& r.queue.mOrderedBroadcasts.get(0) == r) {
- // In this case, we are ready to process the next receiver for the current broadcast,
- // but are on a queue that would like to wait for services to finish before moving
- // on. If there are background services currently starting, then we will go into a
- // special state where we hold off on continuing this broadcast until they are done.
- if (mService.mServices.hasBackgroundServices(r.userId)) {
- Slog.i(ActivityManagerService.TAG, "Delay finish: "
- + r.curComponent.flattenToShortString());
- r.state = BroadcastRecord.WAITING_SERVICES;
- return false;
+ ActivityInfo nextReceiver;
+ if (r.nextReceiver < r.receivers.size()) {
+ Object obj = r.receivers.get(r.nextReceiver);
+ nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo)obj : null;
+ } else {
+ nextReceiver = null;
+ }
+ // Don't do this if the next receive is in the same process as the current one.
+ if (receiver == null || nextReceiver == null
+ || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
+ || !receiver.processName.equals(nextReceiver.processName)) {
+ // In this case, we are ready to process the next receiver for the current broadcast,
+ // but are on a queue that would like to wait for services to finish before moving
+ // on. If there are background services currently starting, then we will go into a
+ // special state where we hold off on continuing this broadcast until they are done.
+ if (mService.mServices.hasBackgroundServices(r.userId)) {
+ Slog.i(ActivityManagerService.TAG, "Delay finish: "
+ + r.curComponent.flattenToShortString());
+ r.state = BroadcastRecord.WAITING_SERVICES;
+ return false;
+ }
}
}
// Is this receiver's application already running?
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
- info.activityInfo.applicationInfo.uid);
+ info.activityInfo.applicationInfo.uid, false);
if (app != null && app.thread != null) {
try {
app.addPackage(info.activityInfo.packageName, mService.mProcessStats);
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
"broadcast", r.curComponent,
- (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false))
+ (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
== null) {
// Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next.
private final long mTotalMemMb;
+ private long mCachedRestoreLevel;
+
private boolean mHaveDisplaySize;
ProcessList() {
}
}
+ // The maximum size we will restore a process from cached to background, when under
+ // memory duress, is 1/3 the size we have reserved for kernel caches and other overhead
+ // before killing background processes.
+ mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024) / 3;
+
for (int i=0; i<mOomAdj.length; i++) {
if (i > 0) {
adjString.append(',');
}
}
+ public static String makeProcStateString(int curProcState) {
+ String procState;
+ switch (curProcState) {
+ case -1:
+ procState = "N ";
+ break;
+ case ActivityManager.PROCESS_STATE_PERSISTENT:
+ procState = "P ";
+ break;
+ case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
+ procState = "PU";
+ break;
+ case ActivityManager.PROCESS_STATE_TOP:
+ procState = "T ";
+ break;
+ case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
+ procState = "IF";
+ break;
+ case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+ procState = "IB";
+ break;
+ case ActivityManager.PROCESS_STATE_BACKUP:
+ procState = "BU";
+ break;
+ case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
+ procState = "HW";
+ break;
+ case ActivityManager.PROCESS_STATE_SERVICE:
+ procState = "S ";
+ break;
+ case ActivityManager.PROCESS_STATE_RECEIVER:
+ procState = "R ";
+ break;
+ case ActivityManager.PROCESS_STATE_HOME:
+ procState = "HO";
+ break;
+ case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
+ procState = "LA";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+ procState = "CA";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ procState = "Ca";
+ break;
+ case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
+ procState = "CE";
+ break;
+ default:
+ procState = "??";
+ break;
+ }
+ return procState;
+ }
+
+ public static void appendRamKb(StringBuilder sb, long ramKb) {
+ for (int j=0, fact=10; j<6; j++, fact*=10) {
+ if (ramKb < fact) {
+ sb.append(' ');
+ }
+ }
+ sb.append(ramKb);
+ }
+
// The minimum amount of time after a state change it is safe ro collect PSS.
public static final int PSS_MIN_TIME_FROM_STATE_CHANGE = 15*1000;
private static final int PSS_SHORT_INTERVAL = 2*60*1000;
// The amount of time until PSS when a process first becomes top.
- private static final int PSS_FIRST_TOP_INTERVAL = 15*1000;
+ private static final int PSS_FIRST_TOP_INTERVAL = 10*1000;
+
+ // The amount of time until PSS when a process first goes into the background.
+ private static final int PSS_FIRST_BACKGROUND_INTERVAL = 20*1000;
// The amount of time until PSS when a process first becomes cached.
- private static final int PSS_FIRST_CACHED_INTERVAL = 5*60*1000;
+ private static final int PSS_FIRST_CACHED_INTERVAL = 30*1000;
// The amount of time until PSS when an important process stays in the same state.
private static final int PSS_SAME_IMPORTANT_INTERVAL = 15*60*1000;
PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_PERSISTENT
PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_PERSISTENT_UI
PSS_FIRST_TOP_INTERVAL, // ActivityManager.PROCESS_STATE_TOP
- PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
- PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
- PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP
- PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
- PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE
- PSS_SHORT_INTERVAL, // ActivityManager.PROCESS_STATE_RECEIVER
+ PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+ PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+ PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP
+ PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
+ PSS_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE
+ PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_RECEIVER
PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_HOME
PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
PSS_FIRST_CACHED_INTERVAL, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
return sProcStateToProcMem[procState1] != sProcStateToProcMem[procState2];
}
- public static String makeProcStateString(int curProcState) {
- String procState;
- switch (curProcState) {
- case -1:
- procState = "N ";
- break;
- case ActivityManager.PROCESS_STATE_PERSISTENT:
- procState = "P ";
- break;
- case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
- procState = "PU";
- break;
- case ActivityManager.PROCESS_STATE_TOP:
- procState = "T ";
- break;
- case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
- procState = "IF";
- break;
- case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
- procState = "IB";
- break;
- case ActivityManager.PROCESS_STATE_BACKUP:
- procState = "BU";
- break;
- case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
- procState = "HW";
- break;
- case ActivityManager.PROCESS_STATE_SERVICE:
- procState = "S ";
- break;
- case ActivityManager.PROCESS_STATE_RECEIVER:
- procState = "R ";
- break;
- case ActivityManager.PROCESS_STATE_HOME:
- procState = "HO";
- break;
- case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
- procState = "LA";
- break;
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
- procState = "CA";
- break;
- case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
- procState = "Ca";
- break;
- case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
- procState = "CE";
- break;
- default:
- procState = "??";
- break;
- }
- return procState;
- }
-
- public static void appendRamKb(StringBuilder sb, long ramKb) {
- for (int j=0, fact=10; j<6; j++, fact*=10) {
- if (ramKb < fact) {
- sb.append(' ');
- }
- }
- sb.append(ramKb);
- }
-
public static long computeNextPssTime(int procState, boolean first, boolean sleeping,
long now) {
final long[] table = sleeping
return mOomMinFree[mOomAdj.length-1] * 1024;
}
+ /**
+ * Return the maximum pss size in kb that we consider a process acceptable to
+ * restore from its cached state for running in the background when RAM is low.
+ */
+ long getCachedRestoreThreshold() {
+ return mCachedRestoreLevel;
+ }
+
private void writeFile(String path, String data) {
FileOutputStream fos = null;
try {
int pid; // The process of this application; 0 if none
boolean starting; // True if the process is being started
long lastActivityTime; // For managing the LRU list
- long lruWeight; // Weight for ordering in LRU list
long lastPssTime; // Last time we retrieved PSS data
long nextPssTime; // Next time we want to request PSS data
long lastStateTime; // Last time setProcState changed
long initialIdlePss; // Initial memory pss of process for idle maintenance.
long lastPss; // Last computed memory pss.
+ long lastCachedPss; // Last computed pss when in cached state.
int maxAdj; // Maximum OOM adjustment for this process
int curRawAdj; // Current OOM unlimited adjustment for this process
int setRawAdj; // Last set OOM unlimited adjustment for this process
pw.println(starting);
pw.print(prefix); pw.print("lastActivityTime=");
TimeUtils.formatDuration(lastActivityTime, now, pw);
- pw.print(" lruWeight="); pw.println(lruWeight);
+ pw.print(" lastPssTime=");
+ TimeUtils.formatDuration(lastPssTime, now, pw);
+ pw.print(" nextPssTime=");
+ TimeUtils.formatDuration(nextPssTime, now, pw);
+ pw.println();
+ pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
+ pw.print(" lruSeq="); pw.print(lruSeq);
+ pw.print(" lastPss="); pw.print(lastPss);
+ pw.print(" lastCachedPss="); pw.println(lastCachedPss);
pw.print(prefix); pw.print("serviceb="); pw.print(serviceb);
pw.print(" keeping="); pw.print(keeping);
pw.print(" cached="); pw.print(cached);
pw.print(" empty="); pw.println(empty);
if (notCachedSinceIdle) {
pw.print(prefix); pw.print("notCachedSinceIdle="); pw.print(notCachedSinceIdle);
- pw.print(" initialIdlePss="); pw.print(initialIdlePss);
- pw.print(" lastPss="); pw.println(lastPss);
+ pw.print(" initialIdlePss="); pw.println(initialIdlePss);
}
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
pw.print(" curRaw="); pw.print(curRawAdj);
pw.print(" lastStateTime=");
TimeUtils.formatDuration(lastStateTime, now, pw);
pw.println();
- pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
- pw.print(" lruSeq="); pw.print(lruSeq);
- pw.print(" lastPssTime=");
- TimeUtils.formatDuration(lastPssTime, now, pw);
- pw.print(" nextPssTime=");
- TimeUtils.formatDuration(nextPssTime, now, pw);
- pw.println();
if (hasShownUi || pendingUiClean || hasAboveClient) {
pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
pw.print(" pendingUiClean="); pw.print(pendingUiClean);