diff options
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. |