diff options
author | Dianne Hackborn <hackbod@google.com> | 2013-06-07 13:25:29 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2013-06-07 15:09:17 -0700 |
commit | be4e6aaa0252dd7da28b7aa85beba982538efa46 (patch) | |
tree | aaa5181a0b440608a1ce783a37076635ce10bafc /services/java/com/android | |
parent | 2df804462b5730b5889ddf6fb993d804edfbee81 (diff) | |
download | frameworks_base-be4e6aaa0252dd7da28b7aa85beba982538efa46.zip frameworks_base-be4e6aaa0252dd7da28b7aa85beba982538efa46.tar.gz frameworks_base-be4e6aaa0252dd7da28b7aa85beba982538efa46.tar.bz2 |
Initial super-primitive process tracker.
The goal of this is to keep track of what app processes
are doing, to determine who is being abusive, when the system
is getting into memory constrained situations, and help the
user determine how to resolve this.
Right now it doesn't really do any of that, just keeps track
of how long every process has been running since boot.
Also update the activity manager to use "cached" as the terminology
for what it used to interchangeably call hidden and background
processes, and switch ProcessMap over to using ArrayMap.
Change-Id: I270b0006aab1f38e17b7d9b65728679173c343f2
Diffstat (limited to 'services/java/com/android')
39 files changed, 464 insertions, 507 deletions
diff --git a/services/java/com/android/server/ProcessMap.java b/services/java/com/android/server/ProcessMap.java index 6b26403..20c97ba 100644 --- a/services/java/com/android/server/ProcessMap.java +++ b/services/java/com/android/server/ProcessMap.java @@ -16,13 +16,12 @@ package com.android.server; +import android.util.ArrayMap; import android.util.SparseArray; -import java.util.HashMap; - public class ProcessMap<E> { - final HashMap<String, SparseArray<E>> mMap - = new HashMap<String, SparseArray<E>>(); + final ArrayMap<String, SparseArray<E>> mMap + = new ArrayMap<String, SparseArray<E>>(); public E get(String name, int uid) { SparseArray<E> uids = mMap.get(name); @@ -50,7 +49,7 @@ public class ProcessMap<E> { } } - public HashMap<String, SparseArray<E>> getMap() { + public ArrayMap<String, SparseArray<E>> getMap() { return mMap; } } diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index a77379e..98c4352 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -57,7 +57,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; -public class ActiveServices { +public final class ActiveServices { static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE; static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING; static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index bb20174..f06b9a6 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -26,6 +26,7 @@ import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; import android.app.AppOpsManager; import android.appwidget.AppWidgetManager; +import android.util.ArrayMap; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; @@ -401,6 +402,12 @@ public final class ActivityManagerService extends ActivityManagerNative final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>(); /** + * Tracking long-term execution of processes to look for abuse and other + * bad app behavior. + */ + final ProcessTracker mProcessTracker = new ProcessTracker(); + + /** * The currently running isolated processes. */ final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<ProcessRecord>(); @@ -614,8 +621,8 @@ public final class ActivityManagerService extends ActivityManagerNative * by the user ID the sticky is for, and can include UserHandle.USER_ALL * for stickies that are sent to all users. */ - final SparseArray<HashMap<String, ArrayList<Intent>>> mStickyBroadcasts = - new SparseArray<HashMap<String, ArrayList<Intent>>>(); + final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts = + new SparseArray<ArrayMap<String, ArrayList<Intent>>>(); final ActiveServices mServices; @@ -803,16 +810,16 @@ public final class ActivityManagerService extends ActivityManagerNative int mLruSeq = 0; /** - * Keep track of the non-hidden/empty process we last found, to help - * determine how to distribute hidden/empty processes next time. + * Keep track of the non-cached/empty process we last found, to help + * determine how to distribute cached/empty processes next time. */ - int mNumNonHiddenProcs = 0; + int mNumNonCachedProcs = 0; /** - * Keep track of the number of hidden procs, to balance oom adj + * Keep track of the number of cached procs, to balance oom adj * distribution between those and empty procs. */ - int mNumHiddenProcs = 0; + int mNumCachedProcs = 0; /** * Keep track of the number of service processes we last found, to @@ -895,7 +902,7 @@ public final class ActivityManagerService extends ActivityManagerNative */ boolean mBooted = false; - int mProcessLimit = ProcessList.MAX_HIDDEN_APPS; + int mProcessLimit = ProcessList.MAX_CACHED_APPS; int mProcessLimitOverride = -1; WindowManagerService mWindowManager; @@ -1476,6 +1483,7 @@ public final class ActivityManagerService extends ActivityManagerNative ServiceManager.addService("meminfo", new MemBinder(m)); ServiceManager.addService("gfxinfo", new GraphicsBinder(m)); ServiceManager.addService("dbinfo", new DbBinder(m)); + ServiceManager.addService("procstats", new ProcBinder(m)); if (MONITOR_CPU_USAGE) { ServiceManager.addService("cpuinfo", new CpuBinder(m)); } @@ -1692,6 +1700,26 @@ public final class ActivityManagerService extends ActivityManagerNative } } + static class ProcBinder extends Binder { + ActivityManagerService mActivityManagerService; + ProcBinder(ActivityManagerService activityManagerService) { + mActivityManagerService = activityManagerService; + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump procstats from from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() + + " without permission " + android.Manifest.permission.DUMP); + return; + } + + mActivityManagerService.dumpProcessTracker(fd, pw, args); + } + } + private ActivityManagerService() { Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); @@ -1780,7 +1808,9 @@ public final class ActivityManagerService extends ActivityManagerNative // We need to tell all apps about the system property change. ArrayList<IBinder> procs = new ArrayList<IBinder>(); synchronized(this) { - for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) { + final int NP = mProcessNames.getMap().size(); + for (int ip=0; ip<NP; ip++) { + SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip); final int NA = apps.size(); for (int ia=0; ia<NA; ia++) { ProcessRecord app = apps.valueAt(ia); @@ -2000,22 +2030,22 @@ public final class ActivityManagerService extends ActivityManagerNative // 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" hidden processes. - skipTop = ProcessList.MIN_HIDDEN_APPS; + // 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" hidden processes. - skipTop = ProcessList.MIN_HIDDEN_APPS; + // 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 hidden. - if (skipTop > 0 && p.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { + // 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) { @@ -3179,7 +3209,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean haveBg = false; for (int i=mLruProcesses.size()-1; i>=0; i--) { ProcessRecord rec = mLruProcesses.get(i); - if (rec.thread != null && rec.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { + if (rec.thread != null && rec.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) { haveBg = true; break; } @@ -3703,7 +3733,9 @@ public final class ActivityManagerService extends ActivityManagerNative try { synchronized(this) { ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(); - for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) { + final int NP = mProcessNames.getMap().size(); + for (int ip=0; ip<NP; ip++) { + SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip); final int NA = apps.size(); for (int ia=0; ia<NA; ia++) { ProcessRecord app = apps.valueAt(ia); @@ -3713,7 +3745,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (app.removed) { procs.add(app); - } else if (app.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { + } else if (app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) { app.removed = true; procs.add(app); } @@ -3940,7 +3972,9 @@ public final class ActivityManagerService extends ActivityManagerNative // same UID (except for the system or root user), and all whose name // matches the package name. final String procNamePrefix = packageName != null ? (packageName + ":") : null; - for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) { + final int NP = mProcessNames.getMap().size(); + for (int ip=0; ip<NP; ip++) { + SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip); final int NA = apps.size(); for (int ia=0; ia<NA; ia++) { ProcessRecord app = apps.valueAt(ia); @@ -4026,9 +4060,9 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "Force stopping u" + userId + ": " + reason); } - Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator(); - while (badApps.hasNext()) { - SparseArray<Long> ba = badApps.next(); + final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap(); + for (int ip=pmap.size()-1; ip>=0; ip--) { + SparseArray<Long> ba = pmap.valueAt(ip); for (i=ba.size()-1; i>=0; i--) { boolean remove = false; final int entUid = ba.keyAt(i); @@ -4050,7 +4084,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } if (ba.size() == 0) { - badApps.remove(); + pmap.removeAt(ip); } } } @@ -4974,7 +5008,7 @@ public final class ActivityManagerService extends ActivityManagerNative enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT, "setProcessLimit()"); synchronized (this) { - mProcessLimit = max < 0 ? ProcessList.MAX_HIDDEN_APPS : max; + mProcessLimit = max < 0 ? ProcessList.MAX_CACHED_APPS : max; mProcessLimitOverride = max; } trimApplications(); @@ -5945,12 +5979,12 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) { final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ); - final long hiddenAppMem = mProcessList.getMemLevel(ProcessList.HIDDEN_APP_MIN_ADJ); + final long cachedAppMem = mProcessList.getMemLevel(ProcessList.CACHED_APP_MIN_ADJ); outInfo.availMem = Process.getFreeMemory(); outInfo.totalMem = Process.getTotalMemory(); outInfo.threshold = homeAppMem; - outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((hiddenAppMem-homeAppMem)/2)); - outInfo.hiddenAppThreshold = hiddenAppMem; + outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((cachedAppMem-homeAppMem)/2)); + outInfo.hiddenAppThreshold = cachedAppMem; outInfo.secondaryServerThreshold = mProcessList.getMemLevel( ProcessList.SERVICE_ADJ); outInfo.visibleAppThreshold = mProcessList.getMemLevel( @@ -6177,10 +6211,11 @@ public final class ActivityManagerService extends ActivityManagerNative // Find any running processes associated with this app. final String pkg = component.getPackageName(); ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(); - HashMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap(); - for (SparseArray<ProcessRecord> uids : pmap.values()) { - for (int i=0; i<uids.size(); i++) { - ProcessRecord proc = uids.valueAt(i); + ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap(); + for (int i=0; i<pmap.size(); i++) { + SparseArray<ProcessRecord> uids = pmap.valueAt(i); + for (int j=0; j<uids.size(); j++) { + ProcessRecord proc = uids.valueAt(j); if (proc.userId != tr.userId) { continue; } @@ -7279,7 +7314,8 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (stats) { ps = stats.getProcessStatsLocked(info.uid, proc); } - return new ProcessRecord(ps, thread, info, proc, uid); + return new ProcessRecord(ps, thread, info, proc, uid, + mProcessTracker.getStateLocked(info.processName, info.uid)); } final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) { @@ -7908,11 +7944,11 @@ public final class ActivityManagerService extends ActivityManagerNative } } - // If the worst oom_adj is somewhere in the hidden proc LRU range, - // then constrain it so we will kill all hidden procs. - if (worstType < ProcessList.HIDDEN_APP_MAX_ADJ - && worstType > ProcessList.HIDDEN_APP_MIN_ADJ) { - worstType = ProcessList.HIDDEN_APP_MIN_ADJ; + // If the worst oom_adj is somewhere in the cached proc LRU range, + // then constrain it so we will kill all cached procs. + if (worstType < ProcessList.CACHED_APP_MAX_ADJ + && worstType > ProcessList.CACHED_APP_MIN_ADJ) { + worstType = ProcessList.CACHED_APP_MIN_ADJ; } // If this is not a secure call, don't let it kill processes that @@ -8815,7 +8851,9 @@ public final class ActivityManagerService extends ActivityManagerNative } synchronized (this) { - for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) { + final int NP = mProcessNames.getMap().size(); + for (int ip=0; ip<NP; ip++) { + SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip); final int NA = apps.size(); for (int ia=0; ia<NA; ia++) { ProcessRecord p = apps.valueAt(ia); @@ -9174,9 +9212,9 @@ public final class ActivityManagerService extends ActivityManagerNative } static int oomAdjToImportance(int adj, ActivityManager.RunningAppProcessInfo currApp) { - if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) { + if (adj >= ProcessList.CACHED_APP_MIN_ADJ) { if (currApp != null) { - currApp.lru = adj - ProcessList.HIDDEN_APP_MIN_ADJ + 1; + currApp.lru = adj - ProcessList.CACHED_APP_MIN_ADJ + 1; } return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; } else if (adj >= ProcessList.SERVICE_B_ADJ) { @@ -9585,7 +9623,9 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)"); if (dumpAll) { - for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) { + final int NP = mProcessNames.getMap().size(); + for (int ip=0; ip<NP; ip++) { + SparseArray<ProcessRecord> procs = mProcessNames.getMap().valueAt(ip); final int NA = procs.size(); for (int ia=0; ia<NA; ia++) { ProcessRecord r = procs.valueAt(ia); @@ -9715,10 +9755,11 @@ public final class ActivityManagerService extends ActivityManagerNative if (mProcessCrashTimes.getMap().size() > 0) { boolean printed = false; long now = SystemClock.uptimeMillis(); - for (Map.Entry<String, SparseArray<Long>> procs - : mProcessCrashTimes.getMap().entrySet()) { - String pname = procs.getKey(); - SparseArray<Long> uids = procs.getValue(); + final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap(); + final int NP = pmap.size(); + for (int ip=0; ip<NP; ip++) { + String pname = pmap.keyAt(ip); + SparseArray<Long> uids = pmap.valueAt(ip); final int N = uids.size(); for (int i=0; i<N; i++) { int puid = uids.keyAt(i); @@ -9745,10 +9786,11 @@ public final class ActivityManagerService extends ActivityManagerNative if (mBadProcesses.getMap().size() > 0) { boolean printed = false; - for (Map.Entry<String, SparseArray<Long>> procs - : mBadProcesses.getMap().entrySet()) { - String pname = procs.getKey(); - SparseArray<Long> uids = procs.getValue(); + final ArrayMap<String, SparseArray<Long>> pmap = mBadProcesses.getMap(); + final int NP = pmap.size(); + for (int ip=0; ip<NP; ip++) { + String pname = pmap.keyAt(ip); + SparseArray<Long> uids = pmap.valueAt(ip); final int N = uids.size(); for (int i=0; i<N; i++) { int puid = uids.keyAt(i); @@ -9915,8 +9957,8 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" mGoingToSleep=" + mStackSupervisor.mGoingToSleep); pw.println(" mLaunchingActivity=" + getFocusedStack().mLaunchingActivity); pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq); - pw.println(" mNumNonHiddenProcs=" + mNumNonHiddenProcs - + " mNumHiddenProcs=" + mNumHiddenProcs + pw.println(" mNumNonCachedProcs=" + mNumNonCachedProcs + + " mNumCachedProcs=" + mNumCachedProcs + " mNumServiceProcs=" + mNumServiceProcs + " mNewNumServiceProcs=" + mNewNumServiceProcs); } @@ -9975,8 +10017,8 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(" HOME_APP_ADJ: "); pw.println(ProcessList.HOME_APP_ADJ); pw.print(" PREVIOUS_APP_ADJ: "); pw.println(ProcessList.PREVIOUS_APP_ADJ); pw.print(" SERVICE_B_ADJ: "); pw.println(ProcessList.SERVICE_B_ADJ); - pw.print(" HIDDEN_APP_MIN_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MIN_ADJ); - pw.print(" HIDDEN_APP_MAX_ADJ: "); pw.println(ProcessList.HIDDEN_APP_MAX_ADJ); + pw.print(" CACHED_APP_MIN_ADJ: "); pw.println(ProcessList.CACHED_APP_MIN_ADJ); + pw.print(" CACHED_APP_MAX_ADJ: "); pw.println(ProcessList.CACHED_APP_MAX_ADJ); if (needSep) pw.println(); needSep = true; @@ -10462,8 +10504,8 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=list.size()-1; i>=0; i--) { ProcessRecord r = list.get(i).first; String oomAdj; - if (r.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { - oomAdj = buildOomTag("bak", " ", r.setAdj, ProcessList.HIDDEN_APP_MIN_ADJ); + if (r.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) { + oomAdj = buildOomTag("cch", " ", r.setAdj, ProcessList.CACHED_APP_MIN_ADJ); } else if (r.setAdj >= ProcessList.SERVICE_B_ADJ) { oomAdj = buildOomTag("svcb ", null, r.setAdj, ProcessList.SERVICE_B_ADJ); } else if (r.setAdj >= ProcessList.PREVIOUS_APP_ADJ) { @@ -10538,8 +10580,8 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(prefix); pw.print(" "); pw.print("oom: max="); pw.print(r.maxAdj); - pw.print(" hidden="); pw.print(r.hiddenAdj); - pw.print(" client="); pw.print(r.clientHiddenAdj); + pw.print(" cached="); pw.print(r.cachedAdj); + pw.print(" client="); pw.print(r.clientCachedAdj); pw.print(" empty="); pw.print(r.emptyAdj); pw.print(" curRaw="); pw.print(r.curRawAdj); pw.print(" setRaw="); pw.print(r.setRawAdj); @@ -10548,7 +10590,7 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(prefix); pw.print(" "); pw.print("keeping="); pw.print(r.keeping); - pw.print(" hidden="); pw.print(r.hidden); + pw.print(" cached="); pw.print(r.cached); pw.print(" empty="); pw.print(r.empty); pw.print(" hasAboveClient="); pw.println(r.hasAboveClient); @@ -10760,13 +10802,13 @@ public final class ActivityManagerService extends ActivityManagerNative ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ, ProcessList.FOREGROUND_APP_ADJ, ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ, ProcessList.BACKUP_APP_ADJ, ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ, - ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.HIDDEN_APP_MAX_ADJ + ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MAX_ADJ }; static final String[] DUMP_MEM_OOM_LABEL = new String[] { "System", "Persistent", "Foreground", "Visible", "Perceptible", "Heavy Weight", "Backup", "A Services", "Home", "Previous", - "B Services", "Background" + "B Services", "Cached" }; final void dumpApplicationMemoryUsage(FileDescriptor fd, @@ -11034,6 +11076,13 @@ public final class ActivityManagerService extends ActivityManagerNative return false; } + final void dumpProcessTracker(FileDescriptor fd, PrintWriter pw, String[] args) { + synchronized (this) { + pw.println("Process Stats:"); + mProcessTracker.dumpLocked(fd, pw, args); + } + } + private final boolean removeDyingProviderLocked(ProcessRecord proc, ContentProviderRecord cpr, boolean always) { final boolean inLaunching = mLaunchingProviders.contains(cpr); @@ -11679,7 +11728,7 @@ public final class ActivityManagerService extends ActivityManagerNative private final List getStickiesLocked(String action, IntentFilter filter, List cur, int userId) { final ContentResolver resolver = mContext.getContentResolver(); - HashMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); + ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); if (stickies == null) { return cur; } @@ -12187,7 +12236,7 @@ public final class ActivityManagerService extends ActivityManagerNative // But first, if this is not a broadcast to all users, then // make sure it doesn't conflict with an existing broadcast to // all users. - HashMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get( + ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get( UserHandle.USER_ALL); if (stickies != null) { ArrayList<Intent> list = stickies.get(intent.getAction()); @@ -12204,9 +12253,9 @@ public final class ActivityManagerService extends ActivityManagerNative } } } - HashMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); + ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); if (stickies == null) { - stickies = new HashMap<String, ArrayList<Intent>>(); + stickies = new ArrayMap<String, ArrayList<Intent>>(); mStickyBroadcasts.put(userId, stickies); } ArrayList<Intent> list = stickies.get(intent.getAction()); @@ -12459,7 +12508,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, msg); throw new SecurityException(msg); } - HashMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); + ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); if (stickies != null) { ArrayList<Intent> list = stickies.get(intent.getAction()); if (list != null) { @@ -12952,18 +13001,18 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } - private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj, int clientHiddenAdj, + private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, int clientCachedAdj, int emptyAdj, ProcessRecord TOP_APP, boolean recursed, boolean doingAll) { if (mAdjSeq == app.adjSeq) { // This adjustment has already been computed. If we are calling // from the top, we may have already computed our adjustment with - // an earlier hidden adjustment that isn't really for us... if - // so, use the new hidden adjustment. - if (!recursed && app.hidden) { + // an earlier cached adjustment that isn't really for us... if + // so, use the new cached adjustment. + if (!recursed && app.cached) { if (app.hasActivities) { - app.curAdj = app.curRawAdj = app.nonStoppingAdj = hiddenAdj; + app.curAdj = app.curRawAdj = app.nonStoppingAdj = cachedAdj; } else if (app.hasClientActivities) { - app.curAdj = app.curRawAdj = app.nonStoppingAdj = clientHiddenAdj; + app.curAdj = app.curRawAdj = app.nonStoppingAdj = clientCachedAdj; } else { app.curAdj = app.curRawAdj = app.nonStoppingAdj = emptyAdj; } @@ -12974,14 +13023,14 @@ public final class ActivityManagerService extends ActivityManagerNative if (app.thread == null) { app.adjSeq = mAdjSeq; app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; - return (app.curAdj=app.curRawAdj=ProcessList.HIDDEN_APP_MAX_ADJ); + return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ); } app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN; app.adjSource = null; app.adjTarget = null; app.empty = false; - app.hidden = false; + app.cached = false; app.hasClientActivities = false; final int activitiesSize = app.activities.size(); @@ -13059,12 +13108,12 @@ public final class ActivityManagerService extends ActivityManagerNative schedGroup = Process.THREAD_GROUP_DEFAULT; app.adjType = "exec-service"; } else { - // Assume process is hidden (has activities); we will correct + // Assume process is cached (has activities); we will correct // later if this is not the case. - adj = hiddenAdj; + adj = cachedAdj; schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; - app.hidden = true; - app.adjType = "bg-act"; + app.cached = true; + app.adjType = "cch-act"; } boolean hasStoppingActivities = false; @@ -13080,7 +13129,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjType = "visible"; } schedGroup = Process.THREAD_GROUP_DEFAULT; - app.hidden = false; + app.cached = false; app.hasActivities = true; foregroundActivities = true; break; @@ -13089,13 +13138,13 @@ public final class ActivityManagerService extends ActivityManagerNative adj = ProcessList.PERCEPTIBLE_APP_ADJ; app.adjType = "pausing"; } - app.hidden = false; + app.cached = false; foregroundActivities = true; } else if (r.state == ActivityState.STOPPING) { // We will apply the actual adjustment later, because // we want to allow this process to immediately go through // any memory trimming that is in effect. - app.hidden = false; + app.cached = false; foregroundActivities = true; hasStoppingActivities = true; } @@ -13105,16 +13154,16 @@ public final class ActivityManagerService extends ActivityManagerNative } } - if (adj == hiddenAdj && !app.hasActivities) { + if (adj == cachedAdj && !app.hasActivities) { if (app.hasClientActivities) { - adj = clientHiddenAdj; - app.adjType = "bg-client-act"; + adj = clientCachedAdj; + app.adjType = "cch-client-act"; } else { // Whoops, this process is completely empty as far as we know // at this point. adj = emptyAdj; app.empty = true; - app.adjType = "bg-empty"; + app.adjType = "cch-empty"; } } @@ -13122,13 +13171,13 @@ public final class ActivityManagerService extends ActivityManagerNative if (app.foregroundServices) { // The user is aware of this app, so make it visible. adj = ProcessList.PERCEPTIBLE_APP_ADJ; - app.hidden = false; + app.cached = false; app.adjType = "fg-service"; schedGroup = Process.THREAD_GROUP_DEFAULT; } else if (app.forcingToForeground != null) { // The user is aware of this app, so make it visible. adj = ProcessList.PERCEPTIBLE_APP_ADJ; - app.hidden = false; + app.cached = false; app.adjType = "force-fg"; app.adjSource = app.forcingToForeground; schedGroup = Process.THREAD_GROUP_DEFAULT; @@ -13143,7 +13192,7 @@ public final class ActivityManagerService extends ActivityManagerNative // We don't want to kill the current heavy-weight process. adj = ProcessList.HEAVY_WEIGHT_APP_ADJ; schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; - app.hidden = false; + app.cached = false; app.adjType = "heavy"; } @@ -13152,7 +13201,7 @@ public final class ActivityManagerService extends ActivityManagerNative // home app, so we don't want to let it go into the background. adj = ProcessList.HOME_APP_ADJ; schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; - app.hidden = false; + app.cached = false; app.adjType = "home"; } @@ -13163,7 +13212,7 @@ public final class ActivityManagerService extends ActivityManagerNative // a good experience around switching between two apps. adj = ProcessList.PREVIOUS_APP_ADJ; schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; - app.hidden = false; + app.cached = false; app.adjType = "previous"; } @@ -13183,7 +13232,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_BACKUP) Slog.v(TAG, "oom BACKUP_APP_ADJ for " + app); adj = ProcessList.BACKUP_APP_ADJ; app.adjType = "backup"; - app.hidden = false; + app.cached = false; } } @@ -13202,7 +13251,7 @@ public final class ActivityManagerService extends ActivityManagerNative // UI stuff. We'll tag it with a label just to help // debug and understand what is going on. if (adj > ProcessList.SERVICE_ADJ) { - app.adjType = "started-bg-ui-services"; + app.adjType = "cch-started-ui-services"; } } else { if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) { @@ -13212,14 +13261,14 @@ public final class ActivityManagerService extends ActivityManagerNative if (adj > ProcessList.SERVICE_ADJ) { adj = ProcessList.SERVICE_ADJ; app.adjType = "started-services"; - app.hidden = false; + app.cached = false; } } // If we have let the service slide into the background // state, still have some text describing what it is doing // even though the service no longer has an impact. if (adj > ProcessList.SERVICE_ADJ) { - app.adjType = "started-bg-services"; + app.adjType = "cch-started-services"; } } // Don't kill this process because it is doing work; it @@ -13245,20 +13294,20 @@ public final class ActivityManagerService extends ActivityManagerNative if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) { ProcessRecord client = cr.binding.client; int clientAdj = adj; - int myHiddenAdj = hiddenAdj; - if (myHiddenAdj > client.hiddenAdj) { - if (client.hiddenAdj >= ProcessList.VISIBLE_APP_ADJ) { - myHiddenAdj = client.hiddenAdj; + int myCachedAdj = cachedAdj; + if (myCachedAdj > client.cachedAdj) { + if (client.cachedAdj >= ProcessList.VISIBLE_APP_ADJ) { + myCachedAdj = client.cachedAdj; } else { - myHiddenAdj = ProcessList.VISIBLE_APP_ADJ; + myCachedAdj = ProcessList.VISIBLE_APP_ADJ; } } - int myClientHiddenAdj = clientHiddenAdj; - if (myClientHiddenAdj > client.clientHiddenAdj) { - if (client.clientHiddenAdj >= ProcessList.VISIBLE_APP_ADJ) { - myClientHiddenAdj = client.clientHiddenAdj; + int myClientCachedAdj = clientCachedAdj; + if (myClientCachedAdj > client.clientCachedAdj) { + if (client.clientCachedAdj >= ProcessList.VISIBLE_APP_ADJ) { + myClientCachedAdj = client.clientCachedAdj; } else { - myClientHiddenAdj = ProcessList.VISIBLE_APP_ADJ; + myClientCachedAdj = ProcessList.VISIBLE_APP_ADJ; } } int myEmptyAdj = emptyAdj; @@ -13269,8 +13318,8 @@ public final class ActivityManagerService extends ActivityManagerNative myEmptyAdj = ProcessList.VISIBLE_APP_ADJ; } } - clientAdj = computeOomAdjLocked(client, myHiddenAdj, - myClientHiddenAdj, myEmptyAdj, TOP_APP, true, doingAll); + clientAdj = computeOomAdjLocked(client, myCachedAdj, + myClientCachedAdj, myEmptyAdj, TOP_APP, true, doingAll); String adjType = null; if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) { // Not doing bind OOM management, so treat @@ -13281,9 +13330,9 @@ public final class ActivityManagerService extends ActivityManagerNative // UI stuff. We'll tag it with a label just to help // debug and understand what is going on. if (adj > clientAdj) { - adjType = "bound-bg-ui-services"; + adjType = "cch-bound-ui-services"; } - app.hidden = false; + app.cached = false; clientAdj = adj; } else { if (now >= (s.lastActivity @@ -13294,7 +13343,7 @@ public final class ActivityManagerService extends ActivityManagerNative // it around. We'll also tag it with a label just // to help debug and undertand what is going on. if (adj > clientAdj) { - adjType = "bound-bg-services"; + adjType = "cch-bound-services"; } clientAdj = adj; } @@ -13305,7 +13354,7 @@ public final class ActivityManagerService extends ActivityManagerNative // created, then we want to try to better follow // its memory management semantics for activities. // That is, if it is sitting in the background - // LRU list as a hidden process (with activities), + // LRU list as a cached process (with activities), // we don't want the service it is connected to // to go into the empty LRU and quickly get killed, // because I'll we'll do is just end up restarting @@ -13323,7 +13372,7 @@ public final class ActivityManagerService extends ActivityManagerNative // memory. if (app.hasShownUi && app != mHomeProcess && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { - adjType = "bound-bg-ui-services"; + adjType = "cch-bound-ui-services"; } else { if ((cr.flags&(Context.BIND_ABOVE_CLIENT |Context.BIND_IMPORTANT)) != 0) { @@ -13340,8 +13389,8 @@ public final class ActivityManagerService extends ActivityManagerNative adj = ProcessList.VISIBLE_APP_ADJ; } } - if (!client.hidden) { - app.hidden = false; + if (!client.cached) { + app.cached = false; } if (client.keeping) { app.keeping = true; @@ -13372,7 +13421,7 @@ public final class ActivityManagerService extends ActivityManagerNative if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) { schedGroup = Process.THREAD_GROUP_DEFAULT; } - app.hidden = false; + app.cached = false; app.adjType = "service"; app.adjTypeCode = ActivityManager.RunningAppProcessInfo .REASON_SERVICE_IN_USE; @@ -13390,10 +13439,10 @@ public final class ActivityManagerService extends ActivityManagerNative // application from running. By default we put the process in // with the rest of the background processes; as we scan through // its services we may bump it up from there. - if (adj > hiddenAdj) { - adj = hiddenAdj; - app.hidden = false; - app.adjType = "bg-services"; + if (adj > cachedAdj) { + adj = cachedAdj; + app.cached = false; + app.adjType = "cch-services"; } } @@ -13412,20 +13461,20 @@ public final class ActivityManagerService extends ActivityManagerNative // Being our own client is not interesting. continue; } - int myHiddenAdj = hiddenAdj; - if (myHiddenAdj > client.hiddenAdj) { - if (client.hiddenAdj > ProcessList.FOREGROUND_APP_ADJ) { - myHiddenAdj = client.hiddenAdj; + int myCachedAdj = cachedAdj; + if (myCachedAdj > client.cachedAdj) { + if (client.cachedAdj > ProcessList.FOREGROUND_APP_ADJ) { + myCachedAdj = client.cachedAdj; } else { - myHiddenAdj = ProcessList.FOREGROUND_APP_ADJ; + myCachedAdj = ProcessList.FOREGROUND_APP_ADJ; } } - int myClientHiddenAdj = clientHiddenAdj; - if (myClientHiddenAdj > client.clientHiddenAdj) { - if (client.clientHiddenAdj >= ProcessList.FOREGROUND_APP_ADJ) { - myClientHiddenAdj = client.clientHiddenAdj; + int myClientCachedAdj = clientCachedAdj; + if (myClientCachedAdj > client.clientCachedAdj) { + if (client.clientCachedAdj >= ProcessList.FOREGROUND_APP_ADJ) { + myClientCachedAdj = client.clientCachedAdj; } else { - myClientHiddenAdj = ProcessList.FOREGROUND_APP_ADJ; + myClientCachedAdj = ProcessList.FOREGROUND_APP_ADJ; } } int myEmptyAdj = emptyAdj; @@ -13436,19 +13485,19 @@ public final class ActivityManagerService extends ActivityManagerNative myEmptyAdj = ProcessList.FOREGROUND_APP_ADJ; } } - int clientAdj = computeOomAdjLocked(client, myHiddenAdj, - myClientHiddenAdj, myEmptyAdj, TOP_APP, true, doingAll); + int clientAdj = computeOomAdjLocked(client, myCachedAdj, + myClientCachedAdj, myEmptyAdj, TOP_APP, true, doingAll); if (adj > clientAdj) { if (app.hasShownUi && app != mHomeProcess && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { - app.adjType = "bg-ui-provider"; + app.adjType = "cch-ui-provider"; } else { adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ ? clientAdj : ProcessList.FOREGROUND_APP_ADJ; app.adjType = "provider"; } - if (!client.hidden) { - app.hidden = false; + if (!client.cached) { + app.cached = false; } if (client.keeping) { app.keeping = true; @@ -13470,7 +13519,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (adj > ProcessList.FOREGROUND_APP_ADJ) { adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; - app.hidden = false; + app.cached = false; app.keeping = true; app.adjType = "provider"; app.adjTarget = cpr.name; @@ -13510,7 +13559,7 @@ public final class ActivityManagerService extends ActivityManagerNative schedGroup = Process.THREAD_GROUP_DEFAULT; } } - if (adj < ProcessList.HIDDEN_APP_MIN_ADJ) { + if (adj < ProcessList.CACHED_APP_MIN_ADJ) { app.keeping = true; } @@ -13526,9 +13575,9 @@ public final class ActivityManagerService extends ActivityManagerNative adj = ProcessList.VISIBLE_APP_ADJ; } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) { adj = ProcessList.PERCEPTIBLE_APP_ADJ; - } else if (adj < ProcessList.HIDDEN_APP_MIN_ADJ) { - adj = ProcessList.HIDDEN_APP_MIN_ADJ; - } else if (adj < ProcessList.HIDDEN_APP_MAX_ADJ) { + } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) { + adj = ProcessList.CACHED_APP_MIN_ADJ; + } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) { adj++; } } @@ -13542,7 +13591,7 @@ public final class ActivityManagerService extends ActivityManagerNative // interesting in this process then we will push it to the // background importance. importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; - } else if (adj >= ProcessList.HIDDEN_APP_MIN_ADJ) { + } else if (adj >= ProcessList.CACHED_APP_MIN_ADJ) { importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND; } else if (adj >= ProcessList.SERVICE_B_ADJ) { importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE; @@ -13848,10 +13897,10 @@ public final class ActivityManagerService extends ActivityManagerNative } } - private final boolean updateOomAdjLocked(ProcessRecord app, int hiddenAdj, - int clientHiddenAdj, int emptyAdj, ProcessRecord TOP_APP, boolean doingAll) { - app.hiddenAdj = hiddenAdj; - app.clientHiddenAdj = clientHiddenAdj; + private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj, + int clientCachedAdj, int emptyAdj, ProcessRecord TOP_APP, boolean doingAll) { + app.cachedAdj = cachedAdj; + app.clientCachedAdj = clientCachedAdj; app.emptyAdj = emptyAdj; if (app.thread == null) { @@ -13862,7 +13911,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean success = true; - computeOomAdjLocked(app, hiddenAdj, clientHiddenAdj, emptyAdj, TOP_APP, false, doingAll); + computeOomAdjLocked(app, cachedAdj, clientCachedAdj, emptyAdj, TOP_APP, false, doingAll); if (app.curRawAdj != app.setRawAdj) { if (wasKeeping && !app.keeping) { @@ -13886,6 +13935,10 @@ public final class ActivityManagerService extends ActivityManagerNative TAG, "Set " + app.pid + " " + app.processName + " adj " + app.curAdj + ": " + app.adjType); app.setAdj = app.curAdj; + if (app.setAdj >= ProcessList.FOREGROUND_APP_ADJ) { + app.tracker.setState(mProcessList.adjToTrackedState(app.setAdj), + SystemClock.uptimeMillis()); + } } else { success = false; Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj); @@ -13937,17 +13990,17 @@ public final class ActivityManagerService extends ActivityManagerNative final ActivityRecord TOP_ACT = resumedAppLocked(); final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; int curAdj = app.curAdj; - final boolean wasHidden = curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ - && curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ; + final boolean wasCached = curAdj >= ProcessList.CACHED_APP_MIN_ADJ + && curAdj <= ProcessList.CACHED_APP_MAX_ADJ; mAdjSeq++; - boolean success = updateOomAdjLocked(app, app.hiddenAdj, app.clientHiddenAdj, + boolean success = updateOomAdjLocked(app, app.cachedAdj, app.clientCachedAdj, app.emptyAdj, TOP_APP, false); - final boolean nowHidden = app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ - && app.curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ; - if (nowHidden != wasHidden) { - // Changed to/from hidden state, so apps after it in the LRU + final boolean nowCached = app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ + && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ; + if (nowCached != wasCached) { + // Changed to/from cached state, so apps after it in the LRU // list may also be changed. updateOomAdjLocked(); } @@ -13969,100 +14022,100 @@ public final class ActivityManagerService extends ActivityManagerNative mNewNumServiceProcs = 0; final int emptyProcessLimit; - final int hiddenProcessLimit; + final int cachedProcessLimit; if (mProcessLimit <= 0) { - emptyProcessLimit = hiddenProcessLimit = 0; + emptyProcessLimit = cachedProcessLimit = 0; } else if (mProcessLimit == 1) { emptyProcessLimit = 1; - hiddenProcessLimit = 0; + cachedProcessLimit = 0; } else { emptyProcessLimit = (mProcessLimit*2)/3; - hiddenProcessLimit = mProcessLimit - emptyProcessLimit; + cachedProcessLimit = mProcessLimit - emptyProcessLimit; } // Let's determine how many processes we have running vs. // how many slots we have for background processes; we may want // to put multiple processes in a slot of there are enough of // them. - int numSlots = (ProcessList.HIDDEN_APP_MAX_ADJ - - ProcessList.HIDDEN_APP_MIN_ADJ + 1) / 2; - int numEmptyProcs = mLruProcesses.size()-mNumNonHiddenProcs-mNumHiddenProcs; - if (numEmptyProcs > hiddenProcessLimit) { - // If there are more empty processes than our limit on hidden - // processes, then use the hidden process limit for the factor. + int numSlots = (ProcessList.CACHED_APP_MAX_ADJ + - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2; + int numEmptyProcs = mLruProcesses.size()- mNumNonCachedProcs - mNumCachedProcs; + if (numEmptyProcs > cachedProcessLimit) { + // If there are more empty processes than our limit on cached + // processes, then use the cached process limit for the factor. // This ensures that the really old empty processes get pushed // down to the bottom, so if we are running low on memory we will - // have a better chance at keeping around more hidden processes + // have a better chance at keeping around more cached processes // instead of a gazillion empty processes. - numEmptyProcs = hiddenProcessLimit; + numEmptyProcs = cachedProcessLimit; } int emptyFactor = numEmptyProcs/numSlots; if (emptyFactor < 1) emptyFactor = 1; - int hiddenFactor = (mNumHiddenProcs > 0 ? mNumHiddenProcs : 1)/numSlots; - if (hiddenFactor < 1) hiddenFactor = 1; - int stepHidden = 0; + int cachedFactor = (mNumCachedProcs > 0 ? mNumCachedProcs : 1)/numSlots; + if (cachedFactor < 1) cachedFactor = 1; + int stepCached = 0; int stepEmpty = 0; - int numHidden = 0; + int numCached = 0; int numEmpty = 0; int numTrimming = 0; - mNumNonHiddenProcs = 0; - mNumHiddenProcs = 0; + mNumNonCachedProcs = 0; + mNumCachedProcs = 0; // First update the OOM adjustment for each of the // application processes based on their current state. int i = mLruProcesses.size(); - int curHiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ; - int nextHiddenAdj = curHiddenAdj+1; - int curEmptyAdj = ProcessList.HIDDEN_APP_MIN_ADJ; + int curCachedAdj = ProcessList.CACHED_APP_MIN_ADJ; + int nextCachedAdj = curCachedAdj+1; + int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ; int nextEmptyAdj = curEmptyAdj+2; - int curClientHiddenAdj = curEmptyAdj; + int curClientCachedAdj = curEmptyAdj; while (i > 0) { i--; ProcessRecord app = mLruProcesses.get(i); - //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj); - updateOomAdjLocked(app, curHiddenAdj, curClientHiddenAdj, curEmptyAdj, TOP_APP, true); + //Slog.i(TAG, "OOM " + app + ": cur cached=" + curCachedAdj); + updateOomAdjLocked(app, curCachedAdj, curClientCachedAdj, curEmptyAdj, TOP_APP, true); if (!app.killedBackground) { - if (app.curRawAdj == curHiddenAdj && app.hasActivities) { - // This process was assigned as a hidden process... step the - // hidden level. - mNumHiddenProcs++; - if (curHiddenAdj != nextHiddenAdj) { - stepHidden++; - if (stepHidden >= hiddenFactor) { - stepHidden = 0; - curHiddenAdj = nextHiddenAdj; - nextHiddenAdj += 2; - if (nextHiddenAdj > ProcessList.HIDDEN_APP_MAX_ADJ) { - nextHiddenAdj = ProcessList.HIDDEN_APP_MAX_ADJ; + if (app.curRawAdj == curCachedAdj && app.hasActivities) { + // This process was assigned as a cached process... step the + // cached level. + mNumCachedProcs++; + if (curCachedAdj != nextCachedAdj) { + stepCached++; + if (stepCached >= cachedFactor) { + stepCached = 0; + curCachedAdj = nextCachedAdj; + nextCachedAdj += 2; + if (nextCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { + nextCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; } - if (curClientHiddenAdj <= curHiddenAdj) { - curClientHiddenAdj = curHiddenAdj + 1; - if (curClientHiddenAdj > ProcessList.HIDDEN_APP_MAX_ADJ) { - curClientHiddenAdj = ProcessList.HIDDEN_APP_MAX_ADJ; + if (curClientCachedAdj <= curCachedAdj) { + curClientCachedAdj = curCachedAdj + 1; + if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { + curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; } } } } - numHidden++; - if (numHidden > hiddenProcessLimit) { + numCached++; + if (numCached > cachedProcessLimit) { Slog.i(TAG, "No longer want " + app.processName - + " (pid " + app.pid + "): hidden #" + numHidden); + + " (pid " + app.pid + "): cached #" + numCached); EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid, app.processName, app.setAdj, "too many background"); app.killedBackground = true; Process.killProcessQuiet(app.pid); } - } else if (app.curRawAdj == curHiddenAdj && app.hasClientActivities) { + } else if (app.curRawAdj == curCachedAdj && app.hasClientActivities) { // This process has a client that has activities. We will have - // given it the current hidden adj; here we will just leave it - // without stepping the hidden adj. - curClientHiddenAdj++; - if (curClientHiddenAdj > ProcessList.HIDDEN_APP_MAX_ADJ) { - curClientHiddenAdj = ProcessList.HIDDEN_APP_MAX_ADJ; + // given it the current cached adj; here we will just leave it + // without stepping the cached adj. + curClientCachedAdj++; + if (curClientCachedAdj > ProcessList.CACHED_APP_MAX_ADJ) { + curClientCachedAdj = ProcessList.CACHED_APP_MAX_ADJ; } } else { - if (app.curRawAdj == curEmptyAdj || app.curRawAdj == curHiddenAdj) { + if (app.curRawAdj == curEmptyAdj || app.curRawAdj == curCachedAdj) { // This process was assigned as an empty process... step the // empty level. if (curEmptyAdj != nextEmptyAdj) { @@ -14071,15 +14124,15 @@ public final class ActivityManagerService extends ActivityManagerNative stepEmpty = 0; curEmptyAdj = nextEmptyAdj; nextEmptyAdj += 2; - if (nextEmptyAdj > ProcessList.HIDDEN_APP_MAX_ADJ) { - nextEmptyAdj = ProcessList.HIDDEN_APP_MAX_ADJ; + if (nextEmptyAdj > ProcessList.CACHED_APP_MAX_ADJ) { + nextEmptyAdj = ProcessList.CACHED_APP_MAX_ADJ; } } } - } else if (app.curRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) { - mNumNonHiddenProcs++; + } else if (app.curRawAdj < ProcessList.CACHED_APP_MIN_ADJ) { + mNumNonCachedProcs++; } - if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ + if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && !app.hasClientActivities) { if (numEmpty > ProcessList.TRIM_EMPTY_APPS && app.lastActivityTime < oldTime) { @@ -14134,9 +14187,9 @@ public final class ActivityManagerService extends ActivityManagerNative // are managing to keep around is less than half the maximum we desire; // if we are keeping a good number around, we'll let them use whatever // memory they want. - if (numHidden <= ProcessList.TRIM_HIDDEN_APPS + if (numCached <= ProcessList.TRIM_CACHED_APPS && numEmpty <= ProcessList.TRIM_EMPTY_APPS) { - final int numHiddenAndEmpty = numHidden + numEmpty; + final int numCachedAndEmpty = numCached + numEmpty; final int N = mLruProcesses.size(); int factor = numTrimming/3; int minFactor = 2; @@ -14145,9 +14198,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (factor < minFactor) factor = minFactor; int step = 0; int fgTrimLevel; - if (numHiddenAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) { + if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) { fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; - } else if (numHiddenAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) { + } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) { fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; } else { fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; @@ -14422,7 +14475,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (proc == null) { - HashMap<String, SparseArray<ProcessRecord>> all + ArrayMap<String, SparseArray<ProcessRecord>> all = mProcessNames.getMap(); SparseArray<ProcessRecord> procs = all.get(process); if (procs != null && procs.size() > 0) { diff --git a/services/java/com/android/server/am/ActivityResult.java b/services/java/com/android/server/am/ActivityResult.java index 12eba34..6d5bdeb 100644 --- a/services/java/com/android/server/am/ActivityResult.java +++ b/services/java/com/android/server/am/ActivityResult.java @@ -23,7 +23,7 @@ import android.os.Bundle; /** * Pending result information to send back to an activity. */ -class ActivityResult extends ResultInfo { +final class ActivityResult extends ResultInfo { final ActivityRecord mFrom; public ActivityResult(ActivityRecord from, String resultWho, diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java index b02a3e8..af61bfb 100644 --- a/services/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/java/com/android/server/am/ActivityStackSupervisor.java @@ -80,7 +80,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -public class ActivityStackSupervisor { +public final class ActivityStackSupervisor { static final boolean DEBUG = ActivityManagerService.DEBUG || false; static final boolean DEBUG_ADD_REMOVE = DEBUG || false; static final boolean DEBUG_APP = DEBUG || false; diff --git a/services/java/com/android/server/am/AppBindRecord.java b/services/java/com/android/server/am/AppBindRecord.java index f1c54fa..06265fd 100644 --- a/services/java/com/android/server/am/AppBindRecord.java +++ b/services/java/com/android/server/am/AppBindRecord.java @@ -23,7 +23,7 @@ import java.util.Iterator; /** * An association between a service and one of its client applications. */ -class AppBindRecord { +final class AppBindRecord { final ServiceRecord service; // The running service. final IntentBindRecord intent; // The intent we are bound to. final ProcessRecord client; // Who has started/bound the service. diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java index ffa1e92..bfc86b0 100644 --- a/services/java/com/android/server/am/AppErrorDialog.java +++ b/services/java/com/android/server/am/AppErrorDialog.java @@ -25,7 +25,7 @@ import android.os.Handler; import android.os.Message; import android.view.WindowManager; -class AppErrorDialog extends BaseErrorDialog { +final class AppErrorDialog extends BaseErrorDialog { private final ActivityManagerService mService; private final AppErrorResult mResult; private final ProcessRecord mProc; diff --git a/services/java/com/android/server/am/AppErrorResult.java b/services/java/com/android/server/am/AppErrorResult.java index ebfcfe2..c6a5720 100644 --- a/services/java/com/android/server/am/AppErrorResult.java +++ b/services/java/com/android/server/am/AppErrorResult.java @@ -16,8 +16,7 @@ package com.android.server.am; - -class AppErrorResult { +final class AppErrorResult { public void set(int res) { synchronized (this) { mHasResult = true; diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java index af61c9b..b5e0715 100644 --- a/services/java/com/android/server/am/AppNotRespondingDialog.java +++ b/services/java/com/android/server/am/AppNotRespondingDialog.java @@ -28,7 +28,7 @@ import android.os.Message; import android.util.Slog; import android.view.WindowManager; -class AppNotRespondingDialog extends BaseErrorDialog { +final class AppNotRespondingDialog extends BaseErrorDialog { private static final String TAG = "AppNotRespondingDialog"; // Event 'what' codes diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java index d08bb10..27865a8 100644 --- a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java +++ b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java @@ -22,7 +22,7 @@ import android.os.Handler; import android.os.Message; import android.view.WindowManager; -class AppWaitingForDebuggerDialog extends BaseErrorDialog { +final class AppWaitingForDebuggerDialog extends BaseErrorDialog { final ActivityManagerService mService; final ProcessRecord mProc; private CharSequence mAppName; diff --git a/services/java/com/android/server/am/BackupRecord.java b/services/java/com/android/server/am/BackupRecord.java index 7e73106..5fa7e6a 100644 --- a/services/java/com/android/server/am/BackupRecord.java +++ b/services/java/com/android/server/am/BackupRecord.java @@ -21,7 +21,7 @@ import com.android.internal.os.BatteryStatsImpl; import android.content.pm.ApplicationInfo; /** @hide */ -class BackupRecord { +final class BackupRecord { // backup/restore modes public static final int BACKUP_NORMAL = 0; public static final int BACKUP_FULL = 1; diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/java/com/android/server/am/BroadcastFilter.java index c631b6e..986b8ea 100644 --- a/services/java/com/android/server/am/BroadcastFilter.java +++ b/services/java/com/android/server/am/BroadcastFilter.java @@ -22,7 +22,7 @@ import android.util.Printer; import java.io.PrintWriter; -class BroadcastFilter extends IntentFilter { +final class BroadcastFilter extends IntentFilter { // Back-pointer to the list this filter is in. final ReceiverList receiverList; final String packageName; diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java index ac7eb89..c7e6010 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/java/com/android/server/am/BroadcastQueue.java @@ -47,7 +47,7 @@ import android.util.Slog; * We keep two broadcast queues and associated bookkeeping, one for those at * foreground priority, and one for normal (background-priority) broadcasts. */ -public class BroadcastQueue { +public final class BroadcastQueue { static final String TAG = "BroadcastQueue"; static final String TAG_MU = ActivityManagerService.TAG_MU; static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST; diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java index 83cc0ea..eb1df6e 100644 --- a/services/java/com/android/server/am/BroadcastRecord.java +++ b/services/java/com/android/server/am/BroadcastRecord.java @@ -36,7 +36,7 @@ import java.util.List; /** * An active intent broadcast. */ -class BroadcastRecord extends Binder { +final class BroadcastRecord extends Binder { final Intent intent; // the original intent that generated us final ComponentName targetComp; // original component name set on the intent final ProcessRecord callerApp; // process that sent this diff --git a/services/java/com/android/server/am/CompatModeDialog.java b/services/java/com/android/server/am/CompatModeDialog.java index 0442bda..202cc7c 100644 --- a/services/java/com/android/server/am/CompatModeDialog.java +++ b/services/java/com/android/server/am/CompatModeDialog.java @@ -28,7 +28,7 @@ import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.Switch; -public class CompatModeDialog extends Dialog { +public final class CompatModeDialog extends Dialog { final ActivityManagerService mService; final ApplicationInfo mAppInfo; diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java index e697f88..f56371c 100644 --- a/services/java/com/android/server/am/CompatModePackages.java +++ b/services/java/com/android/server/am/CompatModePackages.java @@ -25,7 +25,7 @@ import android.util.AtomicFile; import android.util.Slog; import android.util.Xml; -public class CompatModePackages { +public final class CompatModePackages { private final String TAG = ActivityManagerService.TAG; private final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION; diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java index 4ed3c31..dd81493 100644 --- a/services/java/com/android/server/am/ConnectionRecord.java +++ b/services/java/com/android/server/am/ConnectionRecord.java @@ -25,7 +25,7 @@ import java.io.PrintWriter; /** * Description of a single binding to a service. */ -class ConnectionRecord { +final class ConnectionRecord { final AppBindRecord binding; // The application/service binding. final ActivityRecord activity; // If non-null, the owning activity. final IServiceConnection conn; // The client connection. diff --git a/services/java/com/android/server/am/ContentProviderConnection.java b/services/java/com/android/server/am/ContentProviderConnection.java index 7f69b24..f2c9e2f 100644 --- a/services/java/com/android/server/am/ContentProviderConnection.java +++ b/services/java/com/android/server/am/ContentProviderConnection.java @@ -23,7 +23,7 @@ import android.util.TimeUtils; /** * Represents a link between a content provider and client. */ -public class ContentProviderConnection extends Binder { +public final class ContentProviderConnection extends Binder { public final ContentProviderRecord provider; public final ProcessRecord client; public final long createTime; diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java index 8fb6a93..646b7d2 100644 --- a/services/java/com/android/server/am/ContentProviderRecord.java +++ b/services/java/com/android/server/am/ContentProviderRecord.java @@ -33,7 +33,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -class ContentProviderRecord { +final class ContentProviderRecord { final ActivityManagerService service; public final ProviderInfo info; final int uid; diff --git a/services/java/com/android/server/am/CoreSettingsObserver.java b/services/java/com/android/server/am/CoreSettingsObserver.java index 585cf2b..10ea67c 100644 --- a/services/java/com/android/server/am/CoreSettingsObserver.java +++ b/services/java/com/android/server/am/CoreSettingsObserver.java @@ -33,7 +33,7 @@ import java.util.Map; * disk I/O operations. Note: This class assumes that all core settings reside * in {@link Settings.Secure}. */ -class CoreSettingsObserver extends ContentObserver { +final class CoreSettingsObserver extends ContentObserver { private static final String LOG_TAG = CoreSettingsObserver.class.getSimpleName(); // mapping form property name to its type diff --git a/services/java/com/android/server/am/DeviceMonitor.java b/services/java/com/android/server/am/DeviceMonitor.java deleted file mode 100644 index 21e7252..0000000 --- a/services/java/com/android/server/am/DeviceMonitor.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.am; - -import android.os.SELinux; -import android.util.Slog; - -import java.io.*; -import java.util.Arrays; - -/** - * Monitors device resources periodically for some period of time. Useful for - * tracking down performance problems. - */ -class DeviceMonitor { - - private static final String LOG_TAG = DeviceMonitor.class.getName(); - - /** Number of samples to take. */ - private static final int SAMPLE_COUNT = 10; - - /** Time to wait in ms between samples. */ - private static final int INTERVAL = 1000; - - /** Time to wait in ms between samples. */ - private static final int MAX_FILES = 30; - - private final byte[] buffer = new byte[1024]; - - /** Is the monitor currently running? */ - private boolean running = false; - - private DeviceMonitor() { - new Thread() { - public void run() { - monitor(); - } - }.start(); - } - - /** - * Loops continuously. Pauses until someone tells us to start monitoring. - */ - @SuppressWarnings("InfiniteLoopStatement") - private void monitor() { - while (true) { - waitForStart(); - - purge(); - - for (int i = 0; i < SAMPLE_COUNT; i++) { - try { - dump(); - } catch (IOException e) { - Slog.w(LOG_TAG, "Dump failed.", e); - } - pause(); - } - - stop(); - } - } - - private static final File PROC = new File("/proc"); - private static final File BASE = new File("/data/anr/"); - static { - if (!BASE.isDirectory() && !BASE.mkdirs()) { - throw new AssertionError("Couldn't create " + BASE + "."); - } - if (!SELinux.restorecon(BASE)) { - throw new AssertionError("Couldn't restorecon " + BASE + "."); - } - } - - private static final File[] PATHS = { - new File(PROC, "zoneinfo"), - new File(PROC, "interrupts"), - new File(PROC, "meminfo"), - new File(PROC, "slabinfo"), - }; - - - /** - * Deletes old files. - */ - private void purge() { - File[] files = BASE.listFiles(); - int count = files.length - MAX_FILES; - if (count > 0) { - Arrays.sort(files); - for (int i = 0; i < count; i++) { - if (!files[i].delete()) { - Slog.w(LOG_TAG, "Couldn't delete " + files[i] + "."); - } - } - } - } - - /** - * Dumps the current device stats to a new file. - */ - private void dump() throws IOException { - OutputStream out = new FileOutputStream( - new File(BASE, String.valueOf(System.currentTimeMillis()))); - try { - // Copy /proc/*/stat - for (File processDirectory : PROC.listFiles()) { - if (isProcessDirectory(processDirectory)) { - dump(new File(processDirectory, "stat"), out); - } - } - - // Copy other files. - for (File file : PATHS) { - dump(file, out); - } - } finally { - closeQuietly(out); - } - } - - /** - * Returns true if the given file represents a process directory. - */ - private static boolean isProcessDirectory(File file) { - try { - Integer.parseInt(file.getName()); - return file.isDirectory(); - } catch (NumberFormatException e) { - return false; - } - } - - /** - * Copies from a file to an output stream. - */ - private void dump(File from, OutputStream out) throws IOException { - writeHeader(from, out); - - FileInputStream in = null; - try { - in = new FileInputStream(from); - int count; - while ((count = in.read(buffer)) != -1) { - out.write(buffer, 0, count); - } - } finally { - closeQuietly(in); - } - } - - /** - * Writes a header for the given file. - */ - private static void writeHeader(File file, OutputStream out) - throws IOException { - String header = "*** " + file.toString() + "\n"; - out.write(header.getBytes()); - } - - /** - * Closes the given resource. Logs exceptions. - * @param closeable - */ - private static void closeQuietly(Closeable closeable) { - try { - if (closeable != null) { - closeable.close(); - } - } catch (IOException e) { - Slog.w(LOG_TAG, e); - } - } - - /** - * Pauses momentarily before we start the next dump. - */ - private void pause() { - try { - Thread.sleep(INTERVAL); - } catch (InterruptedException e) { /* ignore */ } - } - - /** - * Stops dumping. - */ - private synchronized void stop() { - running = false; - } - - /** - * Waits until someone starts us. - */ - private synchronized void waitForStart() { - while (!running) { - try { - wait(); - } catch (InterruptedException e) { /* ignore */ } - } - } - - /** - * Instructs the monitoring to start if it hasn't already. - */ - private synchronized void startMonitoring() { - if (!running) { - running = true; - notifyAll(); - } - } - - private static DeviceMonitor instance = new DeviceMonitor(); - - /** - * Starts monitoring if it hasn't started already. - */ - static void start() { - instance.startMonitoring(); - } -} diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/java/com/android/server/am/FactoryErrorDialog.java index 0ffb588..f4632c1 100644 --- a/services/java/com/android/server/am/FactoryErrorDialog.java +++ b/services/java/com/android/server/am/FactoryErrorDialog.java @@ -22,7 +22,7 @@ import android.os.Handler; import android.os.Message; import android.view.WindowManager; -class FactoryErrorDialog extends BaseErrorDialog { +final class FactoryErrorDialog extends BaseErrorDialog { public FactoryErrorDialog(Context context, CharSequence msg) { super(context); setCancelable(false); diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java index 0a92964..6c84b9f 100644 --- a/services/java/com/android/server/am/IntentBindRecord.java +++ b/services/java/com/android/server/am/IntentBindRecord.java @@ -27,7 +27,7 @@ import java.util.Iterator; /** * A particular Intent that has been bound to a Service. */ -class IntentBindRecord { +final class IntentBindRecord { /** The running service. */ final ServiceRecord service; /** The intent that is bound.*/ diff --git a/services/java/com/android/server/am/LaunchWarningWindow.java b/services/java/com/android/server/am/LaunchWarningWindow.java index cb2b7bb..30c3066 100644 --- a/services/java/com/android/server/am/LaunchWarningWindow.java +++ b/services/java/com/android/server/am/LaunchWarningWindow.java @@ -26,7 +26,7 @@ import android.view.WindowManager; import android.widget.ImageView; import android.widget.TextView; -public class LaunchWarningWindow extends Dialog { +public final class LaunchWarningWindow extends Dialog { public LaunchWarningWindow(Context context, ActivityRecord cur, ActivityRecord next) { super(context, R.style.Theme_Toast); diff --git a/services/java/com/android/server/am/NativeCrashListener.java b/services/java/com/android/server/am/NativeCrashListener.java index a9454bd..307ab03 100644 --- a/services/java/com/android/server/am/NativeCrashListener.java +++ b/services/java/com/android/server/am/NativeCrashListener.java @@ -40,7 +40,7 @@ import java.net.InetUnixAddress; * * Note that this component runs in a separate thread. */ -class NativeCrashListener extends Thread { +final class NativeCrashListener extends Thread { static final String TAG = "NativeCrashListener"; static final boolean DEBUG = false; static final boolean MORE_DEBUG = DEBUG && false; diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java index 28593fe..17f24a9 100644 --- a/services/java/com/android/server/am/PendingIntentRecord.java +++ b/services/java/com/android/server/am/PendingIntentRecord.java @@ -31,7 +31,7 @@ import android.util.Slog; import java.io.PrintWriter; import java.lang.ref.WeakReference; -class PendingIntentRecord extends IIntentSender.Stub { +final class PendingIntentRecord extends IIntentSender.Stub { final ActivityManagerService owner; final Key key; final int uid; diff --git a/services/java/com/android/server/am/PendingThumbnailsRecord.java b/services/java/com/android/server/am/PendingThumbnailsRecord.java index c460791..e4eb4d0 100644 --- a/services/java/com/android/server/am/PendingThumbnailsRecord.java +++ b/services/java/com/android/server/am/PendingThumbnailsRecord.java @@ -24,7 +24,7 @@ import java.util.HashSet; * This class keeps track of calls to getTasks() that are still * waiting for thumbnail images. */ -class PendingThumbnailsRecord +final class PendingThumbnailsRecord { final IThumbnailReceiver receiver; // who is waiting. final HashSet<ActivityRecord> pendingRecords; // HistoryRecord objects we still wait for. diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java index 1a635a9..e937d35 100644 --- a/services/java/com/android/server/am/ProcessList.java +++ b/services/java/com/android/server/am/ProcessList.java @@ -29,7 +29,7 @@ import android.view.Display; /** * Activity manager code dealing with processes. */ -class ProcessList { +final class ProcessList { // The minimum time we allow between crashes, for us to consider this // application to be bad and stop and its services and reject broadcasts. static final int MIN_CRASH_INTERVAL = 60*1000; @@ -38,8 +38,8 @@ class ProcessList { // This is a process only hosting activities that are not visible, // so it can be killed without any disruption. - static final int HIDDEN_APP_MAX_ADJ = 15; - static int HIDDEN_APP_MIN_ADJ = 9; + static final int CACHED_APP_MAX_ADJ = 15; + static int CACHED_APP_MIN_ADJ = 9; // The B list of SERVICE_ADJ -- these are the old and decrepit // services that aren't as shiny and interesting as the ones in the A list. @@ -94,37 +94,37 @@ class ProcessList { // Memory pages are 4K. static final int PAGE_SIZE = 4*1024; - // The minimum number of hidden apps we want to be able to keep around, + // The minimum number of cached apps we want to be able to keep around, // without empty apps being able to push them out of memory. - static final int MIN_HIDDEN_APPS = 2; + static final int MIN_CACHED_APPS = 2; - // The maximum number of hidden processes we will keep around before + // The maximum number of cached processes we will keep around before // killing them; this is just a control to not let us go too crazy with // keeping around processes on devices with large amounts of RAM. - static final int MAX_HIDDEN_APPS = 24; + static final int MAX_CACHED_APPS = 24; // We allow empty processes to stick around for at most 30 minutes. static final long MAX_EMPTY_TIME = 30*60*1000; - // The number of hidden at which we don't consider it necessary to do + // The number of cached at which we don't consider it necessary to do // memory trimming. - static final int TRIM_HIDDEN_APPS = 3; + static final int TRIM_CACHED_APPS = 3; // The number of empty apps at which we don't consider it necessary to do // memory trimming. static final int TRIM_EMPTY_APPS = 3; - // Threshold of number of hidden+empty where we consider memory critical. + // Threshold of number of cached+empty where we consider memory critical. static final int TRIM_CRITICAL_THRESHOLD = 3; - // Threshold of number of hidden+empty where we consider memory critical. + // Threshold of number of cached+empty where we consider memory critical. static final int TRIM_LOW_THRESHOLD = 5; - // We put empty content processes after any hidden processes that have + // We put empty content processes after any cached processes that have // been idle for less than 15 seconds. static final long CONTENT_APP_IDLE_OFFSET = 15*1000; - // We put empty content processes after any hidden processes that have + // We put empty content processes after any cached processes that have // been idle for less than 120 seconds. static final long EMPTY_APP_IDLE_OFFSET = 120*1000; @@ -133,7 +133,7 @@ class ProcessList { // can't give it a different value for every possible kind of process. private final int[] mOomAdj = new int[] { FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ, - BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, HIDDEN_APP_MAX_ADJ + BACKUP_APP_ADJ, CACHED_APP_MIN_ADJ, CACHED_APP_MAX_ADJ }; // These are the low-end OOM level limits. This is appropriate for an // HVGA or smaller phone with less than 512MB. Values are in KB. @@ -154,11 +154,34 @@ class ProcessList { private boolean mHaveDisplaySize; + private final int[] mAdjToTrackedState = new int[CACHED_APP_MAX_ADJ+1]; + ProcessList() { MemInfoReader minfo = new MemInfoReader(); minfo.readMemInfo(); mTotalMemMb = minfo.getTotalSize()/(1024*1024); updateOomLevels(0, 0, false); + for (int i=0; i<=CACHED_APP_MAX_ADJ; i++) { + if (i <= FOREGROUND_APP_ADJ) { + mAdjToTrackedState[i] = ProcessTracker.STATE_FOREGROUND; + } else if (i <= VISIBLE_APP_ADJ) { + mAdjToTrackedState[i] = ProcessTracker.STATE_VISIBLE; + } else if (i <= PERCEPTIBLE_APP_ADJ) { + mAdjToTrackedState[i] = ProcessTracker.STATE_PERCEPTIBLE; + } else if (i <= BACKUP_APP_ADJ) { + mAdjToTrackedState[i] = ProcessTracker.STATE_BACKUP; + } else if (i <= SERVICE_ADJ) { + mAdjToTrackedState[i] = ProcessTracker.STATE_SERVICE; + } else if (i <= HOME_APP_ADJ) { + mAdjToTrackedState[i] = ProcessTracker.STATE_HOME; + } else if (i <= PREVIOUS_APP_ADJ) { + mAdjToTrackedState[i] = ProcessTracker.STATE_PREVIOUS; + } else if (i <= SERVICE_B_ADJ) { + mAdjToTrackedState[i] = ProcessTracker.STATE_SERVICE; + } else { + mAdjToTrackedState[i] = ProcessTracker.STATE_CACHED; + } + } } void applyDisplaySize(WindowManagerService wm) { @@ -220,6 +243,10 @@ class ProcessList { return mOomMinFree[mOomAdj.length-1] * 1024; } + int adjToTrackedState(int adj) { + return mAdjToTrackedState[adj]; + } + private void writeFile(String path, String data) { FileOutputStream fos = null; try { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 3a4a34c..6cae67c 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -44,13 +44,14 @@ import java.util.HashSet; * Full information about a particular process that * is currently running. */ -class ProcessRecord { +final class ProcessRecord { final BatteryStatsImpl.Uid.Proc batteryStats; // where to collect runtime statistics final ApplicationInfo info; // all about the first app in the process final boolean isolated; // true if this is a special isolated process final int uid; // uid of process; may be different from 'info' if isolated final int userId; // user of process. final String processName; // name of the process + final ProcessTracker.ProcessState tracker; // tracking execution of process // List of packages running in the process final HashSet<String> pkgList = new HashSet<String>(); IApplicationThread thread; // the actual proc... may be null only if @@ -61,8 +62,8 @@ class ProcessRecord { long lastActivityTime; // For managing the LRU list long lruWeight; // Weight for ordering in LRU list int maxAdj; // Maximum OOM adjustment for this process - int hiddenAdj; // If hidden, this is the adjustment to use - int clientHiddenAdj; // If empty but hidden client, this is the adjustment to use + int cachedAdj; // If cached, this is the adjustment to use + int clientCachedAdj; // If empty but cached client, this is the adjustment to use int emptyAdj; // If empty, this is the adjustment to use int curRawAdj; // Current OOM unlimited adjustment for this process int setRawAdj; // Last set OOM unlimited adjustment for this process @@ -108,7 +109,7 @@ class ProcessRecord { long lastLowMemory; // When we last told the app that memory is low boolean reportLowMemory; // Set to true when waiting to report low mem boolean empty; // Is this an empty background process? - boolean hidden; // Is this a hidden process? + boolean cached; // Is this a cached process? int lastPss; // Last pss size reported by app. String adjType; // Debugging: primary thing impacting oom_adj. int adjTypeCode; // Debugging: adj code to report to app. @@ -201,11 +202,11 @@ class ProcessRecord { pw.print(" lruWeight="); pw.print(lruWeight); pw.print(" serviceb="); pw.print(serviceb); pw.print(" keeping="); pw.print(keeping); - pw.print(" hidden="); pw.print(hidden); + pw.print(" cached="); pw.print(cached); pw.print(" empty="); pw.println(empty); pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj); - pw.print(" hidden="); pw.print(hiddenAdj); - pw.print(" client="); pw.print(clientHiddenAdj); + pw.print(" cached="); pw.print(cachedAdj); + pw.print(" client="); pw.print(clientCachedAdj); pw.print(" empty="); pw.print(emptyAdj); pw.print(" curRaw="); pw.print(curRawAdj); pw.print(" setRaw="); pw.print(setRawAdj); @@ -325,17 +326,19 @@ class ProcessRecord { } ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, IApplicationThread _thread, - ApplicationInfo _info, String _processName, int _uid) { + ApplicationInfo _info, String _processName, int _uid, + ProcessTracker.ProcessState _tracker) { batteryStats = _batteryStats; info = _info; isolated = _info.uid != _uid; uid = _uid; userId = UserHandle.getUserId(_uid); processName = _processName; + tracker = _tracker; pkgList.add(_info.packageName); thread = _thread; - maxAdj = ProcessList.HIDDEN_APP_MAX_ADJ; - hiddenAdj = clientHiddenAdj = emptyAdj = ProcessList.HIDDEN_APP_MIN_ADJ; + maxAdj = ProcessList.CACHED_APP_MAX_ADJ; + cachedAdj = clientCachedAdj = emptyAdj = ProcessList.CACHED_APP_MIN_ADJ; curRawAdj = setRawAdj = -100; curAdj = setAdj = -100; persistent = false; diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java new file mode 100644 index 0000000..4eb71c7 --- /dev/null +++ b/services/java/com/android/server/am/ProcessTracker.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import android.os.SystemClock; +import android.util.ArrayMap; +import android.util.SparseArray; +import android.util.TimeUtils; +import com.android.server.ProcessMap; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +public final class ProcessTracker { + public static final int STATE_NOTHING = -1; + public static final int STATE_TOP = 0; + public static final int STATE_FOREGROUND = 1; + public static final int STATE_VISIBLE = 2; + public static final int STATE_PERCEPTIBLE = 3; + public static final int STATE_BACKUP = 4; + public static final int STATE_SERVICE = 5; + public static final int STATE_HOME = 6; + public static final int STATE_PREVIOUS = 7; + public static final int STATE_CACHED = 8; + public static final int STATE_SCREEN_ON_MOD = STATE_CACHED+1; + public static final int STATE_COUNT = STATE_SCREEN_ON_MOD*2; + + static String[] STATE_NAMES = new String[] { + "Top ", "Foreground ", "Visible ", "Perceptible", "Backup ", + "Service ", "Home ", "Previous ", "Cached " + }; + + public static final class ProcessState { + final long[] mTimes = new long[STATE_COUNT]; + int mCurState = STATE_NOTHING; + long mStartTime; + + public void setState(int state, long now) { + if (mCurState != STATE_NOTHING) { + mTimes[mCurState] += now - mStartTime; + } + mCurState = state; + mStartTime = now; + } + } + + static final class State { + final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>(); + } + + final State mState = new State(); + + public ProcessTracker() { + } + + public ProcessState getStateLocked(String name, int uid) { + ProcessState ps = mState.mProcesses.get(name, uid); + if (ps != null) { + return ps; + } + ps = new ProcessState(); + mState.mProcesses.put(name, uid, ps); + return ps; + } + + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { + final long now = SystemClock.uptimeMillis(); + ArrayMap<String, SparseArray<ProcessState>> pmap = mState.mProcesses.getMap(); + for (int ip=0; ip<pmap.size(); ip++) { + String procName = pmap.keyAt(ip); + SparseArray<ProcessState> procs = pmap.valueAt(ip); + for (int iu=0; iu<procs.size(); iu++) { + int uid = procs.keyAt(iu); + ProcessState state = procs.valueAt(iu); + pw.print(" "); pw.print(procName); pw.print(" / "); pw.print(uid); pw.println(":"); + long totalTime = 0; + for (int is=0; is<STATE_NAMES.length; is++) { + long time = state.mTimes[is]; + if (state.mCurState == is) { + time += now - state.mStartTime; + } + if (time != 0) { + pw.print(" "); pw.print(STATE_NAMES[is]); pw.print(": "); + TimeUtils.formatDuration(time, pw); pw.println(); + totalTime += time; + } + } + if (totalTime != 0) { + pw.print(" TOTAL : "); + TimeUtils.formatDuration(totalTime, pw); + pw.println(); + } + } + } + } +} diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java index ee406c8..5759a44 100644 --- a/services/java/com/android/server/am/ProviderMap.java +++ b/services/java/com/android/server/am/ProviderMap.java @@ -35,7 +35,7 @@ import java.util.Map; * Keeps track of content providers by authority (name) and class. It separates the mapping by * user and ones that are not user-specific (system providers). */ -public class ProviderMap { +public final class ProviderMap { private static final String TAG = "ProviderMap"; diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/java/com/android/server/am/ReceiverList.java index 9b6701e..b19cc5d 100644 --- a/services/java/com/android/server/am/ReceiverList.java +++ b/services/java/com/android/server/am/ReceiverList.java @@ -32,7 +32,7 @@ import java.util.ArrayList; * A receiver object that has registered for one or more broadcasts. * The ArrayList holds BroadcastFilter objects. */ -class ReceiverList extends ArrayList<BroadcastFilter> +final class ReceiverList extends ArrayList<BroadcastFilter> implements IBinder.DeathRecipient { final ActivityManagerService owner; public final IIntentReceiver receiver; diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index 707e8ee..45e248b 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -47,7 +47,7 @@ import java.util.List; /** * A running application service. */ -class ServiceRecord extends Binder { +final class ServiceRecord extends Binder { // Maximum number of delivery attempts before giving up. static final int MAX_DELIVERY_COUNT = 3; diff --git a/services/java/com/android/server/am/StrictModeViolationDialog.java b/services/java/com/android/server/am/StrictModeViolationDialog.java index 35d50a1..b6d0daa 100644 --- a/services/java/com/android/server/am/StrictModeViolationDialog.java +++ b/services/java/com/android/server/am/StrictModeViolationDialog.java @@ -25,7 +25,7 @@ import android.os.Handler; import android.os.Message; import android.util.Slog; -class StrictModeViolationDialog extends BaseErrorDialog { +final class StrictModeViolationDialog extends BaseErrorDialog { private final static String TAG = "StrictModeViolationDialog"; private final ActivityManagerService mService; diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java index 58392ef..d03da20 100644 --- a/services/java/com/android/server/am/TaskRecord.java +++ b/services/java/com/android/server/am/TaskRecord.java @@ -33,7 +33,7 @@ import android.util.Slog; import java.io.PrintWriter; import java.util.ArrayList; -class TaskRecord extends ThumbnailHolder { +final class TaskRecord extends ThumbnailHolder { final int taskId; // Unique identifier for this task. final String affinity; // The affinity name for this task, or null. Intent intent; // The original intent that started the task. diff --git a/services/java/com/android/server/am/TransferPipe.java b/services/java/com/android/server/am/TransferPipe.java index c3f4f93..055c577 100644 --- a/services/java/com/android/server/am/TransferPipe.java +++ b/services/java/com/android/server/am/TransferPipe.java @@ -32,7 +32,7 @@ import android.util.Slog; /** * Helper for transferring data through a pipe from a client app. */ -class TransferPipe implements Runnable { +final class TransferPipe implements Runnable { static final String TAG = "TransferPipe"; static final boolean DEBUG = false; diff --git a/services/java/com/android/server/am/UriPermission.java b/services/java/com/android/server/am/UriPermission.java index cba8e0d..5e2ad00 100644 --- a/services/java/com/android/server/am/UriPermission.java +++ b/services/java/com/android/server/am/UriPermission.java @@ -35,7 +35,7 @@ import java.util.HashSet; * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/ * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java */ -class UriPermission { +final class UriPermission { private static final String TAG = "UriPermission"; final int userHandle; diff --git a/services/java/com/android/server/am/UriPermissionOwner.java b/services/java/com/android/server/am/UriPermissionOwner.java index 90ac88d..7bbd3bc 100644 --- a/services/java/com/android/server/am/UriPermissionOwner.java +++ b/services/java/com/android/server/am/UriPermissionOwner.java @@ -24,7 +24,7 @@ import android.os.IBinder; import java.util.HashSet; import java.util.Iterator; -class UriPermissionOwner { +final class UriPermissionOwner { final ActivityManagerService service; final Object owner; diff --git a/services/java/com/android/server/am/UserStartedState.java b/services/java/com/android/server/am/UserStartedState.java index 0e71f81..d3e73d5 100644 --- a/services/java/com/android/server/am/UserStartedState.java +++ b/services/java/com/android/server/am/UserStartedState.java @@ -22,7 +22,7 @@ import java.util.ArrayList; import android.app.IStopUserCallback; import android.os.UserHandle; -public class UserStartedState { +public final class UserStartedState { // User is first coming up. public final static int STATE_BOOTING = 0; // User is in the normal running state. |