diff options
Diffstat (limited to 'services/java/com')
13 files changed, 501 insertions, 202 deletions
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index a5d64b2..912c465 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -1015,7 +1015,7 @@ public final class ActiveServices { Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app); if (app != null && app.thread != null) { try { - app.addPackage(r.appInfo.packageName); + app.addPackage(r.appInfo.packageName, mAm.mProcessTracker); realStartServiceLocked(r, app); return null; } catch (RemoteException e) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 38fe5e6..2124095 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -817,10 +817,10 @@ public final class ActivityManagerService extends ActivityManagerNative int mNumNonCachedProcs = 0; /** - * Keep track of the number of cached procs, to balance oom adj + * Keep track of the number of cached hidden procs, to balance oom adj * distribution between those and empty procs. */ - int mNumCachedProcs = 0; + int mNumCachedHiddenProcs = 0; /** * Keep track of the number of service processes we last found, to @@ -2151,7 +2151,7 @@ public final class ActivityManagerService extends ActivityManagerNative // come up (we have a pid but not yet its thread), so keep it. if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app); // If this is a new package in the process, add the package to the list - app.addPackage(info.packageName); + app.addPackage(info.packageName, mProcessTracker); return app; } @@ -2206,7 +2206,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } else { // If this is a new package in the process, add the package to the list - app.addPackage(info.packageName); + app.addPackage(info.packageName, mProcessTracker); } // If the system is not ready yet, then hold off on starting this @@ -3039,10 +3039,8 @@ public final class ActivityManagerService extends ActivityManagerNative proc = p; break; } - for (String str : p.pkgList) { - if (str.equals(packageName)) { - proc = p; - } + if (p.pkgList.containsKey(packageName)) { + proc = p; } } } @@ -4014,7 +4012,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (userId != UserHandle.USER_ALL && app.userId != userId) { continue; } - if (!app.pkgList.contains(packageName)) { + if (!app.pkgList.containsKey(packageName)) { continue; } } @@ -6220,7 +6218,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (proc.userId != tr.userId) { continue; } - if (!proc.pkgList.contains(pkg)) { + if (!proc.pkgList.containsKey(pkg)) { continue; } procs.add(proc); @@ -6577,7 +6575,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_MU) Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid); app.pubProviders.put(cpi.name, cpr); - app.addPackage(cpi.applicationInfo.packageName); + app.addPackage(cpi.applicationInfo.packageName, mProcessTracker); ensurePackageDexOpt(cpi.applicationInfo.packageName); } } @@ -7316,7 +7314,7 @@ public final class ActivityManagerService extends ActivityManagerNative ps = stats.getProcessStatsLocked(info.uid, proc); } return new ProcessRecord(ps, thread, info, proc, uid, - mProcessTracker.getStateLocked(info.processName, info.uid)); + mProcessTracker.getProcessStateLocked(info.packageName, uid, proc)); } final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) { @@ -8895,7 +8893,8 @@ public final class ActivityManagerService extends ActivityManagerNative int flags = process.info.flags; IPackageManager pm = AppGlobals.getPackageManager(); sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n"); - for (String pkg : process.pkgList) { + for (int ip=0; ip<process.pkgList.size(); ip++) { + String pkg = process.pkgList.keyAt(ip); sb.append("Package: ").append(pkg); try { PackageInfo pi = pm.getPackageInfo(pkg, 0, UserHandle.getCallingUserId()); @@ -9630,7 +9629,7 @@ public final class ActivityManagerService extends ActivityManagerNative final int NA = procs.size(); for (int ia=0; ia<NA; ia++) { ProcessRecord r = procs.valueAt(ia); - if (dumpPackage != null && !r.pkgList.contains(dumpPackage)) { + if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) { continue; } if (!needSep) { @@ -9653,7 +9652,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean printed = false; for (int i=0; i<mIsolatedProcesses.size(); i++) { ProcessRecord r = mIsolatedProcesses.valueAt(i); - if (dumpPackage != null && !r.pkgList.contains(dumpPackage)) { + if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) { continue; } if (!printed) { @@ -9685,7 +9684,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean printed = false; for (int i=0; i<mPidsSelfLocked.size(); i++) { ProcessRecord r = mPidsSelfLocked.valueAt(i); - if (dumpPackage != null && !r.pkgList.contains(dumpPackage)) { + if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) { continue; } if (!printed) { @@ -9708,7 +9707,7 @@ public final class ActivityManagerService extends ActivityManagerNative ProcessRecord r = mPidsSelfLocked.get( mForegroundProcesses.valueAt(i).pid); if (dumpPackage != null && (r == null - || !r.pkgList.contains(dumpPackage))) { + || !r.pkgList.containsKey(dumpPackage))) { continue; } if (!printed) { @@ -9766,7 +9765,7 @@ public final class ActivityManagerService extends ActivityManagerNative int puid = uids.keyAt(i); ProcessRecord r = mProcessNames.get(pname, puid); if (dumpPackage != null && (r == null - || !r.pkgList.contains(dumpPackage))) { + || !r.pkgList.containsKey(dumpPackage))) { continue; } if (!printed) { @@ -9797,7 +9796,7 @@ public final class ActivityManagerService extends ActivityManagerNative int puid = uids.keyAt(i); ProcessRecord r = mProcessNames.get(pname, puid); if (dumpPackage != null && (r == null - || !r.pkgList.contains(dumpPackage))) { + || !r.pkgList.containsKey(dumpPackage))) { continue; } if (!printed) { @@ -9840,7 +9839,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } if (mHomeProcess != null && (dumpPackage == null - || mHomeProcess.pkgList.contains(dumpPackage))) { + || mHomeProcess.pkgList.containsKey(dumpPackage))) { if (needSep) { pw.println(); needSep = false; @@ -9848,7 +9847,7 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" mHomeProcess: " + mHomeProcess); } if (mPreviousProcess != null && (dumpPackage == null - || mPreviousProcess.pkgList.contains(dumpPackage))) { + || mPreviousProcess.pkgList.containsKey(dumpPackage))) { if (needSep) { pw.println(); needSep = false; @@ -9862,7 +9861,7 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(sb); } if (mHeavyWeightProcess != null && (dumpPackage == null - || mHeavyWeightProcess.pkgList.contains(dumpPackage))) { + || mHeavyWeightProcess.pkgList.containsKey(dumpPackage))) { if (needSep) { pw.println(); needSep = false; @@ -9959,7 +9958,8 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" mLaunchingActivity=" + getFocusedStack().mLaunchingActivity); pw.println(" mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq); pw.println(" mNumNonCachedProcs=" + mNumNonCachedProcs - + " mNumCachedProcs=" + mNumCachedProcs + + " (" + mLruProcesses.size() + " total)" + + " mNumCachedHiddenProcs=" + mNumCachedHiddenProcs + " mNumServiceProcs=" + mNumServiceProcs + " mNewNumServiceProcs=" + mNewNumServiceProcs); } @@ -10463,7 +10463,7 @@ public final class ActivityManagerService extends ActivityManagerNative = new ArrayList<Pair<ProcessRecord, Integer>>(origList.size()); for (int i=0; i<origList.size(); i++) { ProcessRecord r = origList.get(i); - if (dumpPackage != null && !r.pkgList.contains(dumpPackage)) { + if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) { continue; } list.add(new Pair<ProcessRecord, Integer>(origList.get(i), i)); @@ -11079,7 +11079,6 @@ public final class ActivityManagerService extends ActivityManagerNative final void dumpProcessTracker(FileDescriptor fd, PrintWriter pw, String[] args) { synchronized (this) { - pw.println("Process Stats:"); mProcessTracker.dumpLocked(fd, pw, args); } } @@ -11787,7 +11786,7 @@ public final class ActivityManagerService extends ActivityManagerNative + ") when registering receiver " + receiver); } if (callerApp.info.uid != Process.SYSTEM_UID && - !callerApp.pkgList.contains(callerPackage)) { + !callerApp.pkgList.containsKey(callerPackage)) { throw new SecurityException("Given caller package " + callerPackage + " is not running in process " + callerApp); } @@ -13899,7 +13898,7 @@ public final class ActivityManagerService extends ActivityManagerNative } private final boolean updateOomAdjLocked(ProcessRecord app, int cachedAdj, - int clientCachedAdj, int emptyAdj, ProcessRecord TOP_APP, boolean doingAll) { + int clientCachedAdj, int emptyAdj, ProcessRecord TOP_APP, boolean doingAll, long now) { app.cachedAdj = cachedAdj; app.clientCachedAdj = clientCachedAdj; app.emptyAdj = emptyAdj; @@ -13936,9 +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()); + app.setAdjChanged = true; + if (!doingAll) { + app.setProcessTrackerState(TOP_APP, mProcessTracker.getMemFactor(), + now, mProcessList); } } else { success = false; @@ -13997,7 +13997,7 @@ public final class ActivityManagerService extends ActivityManagerNative mAdjSeq++; boolean success = updateOomAdjLocked(app, app.cachedAdj, app.clientCachedAdj, - app.emptyAdj, TOP_APP, false); + app.emptyAdj, TOP_APP, false, SystemClock.uptimeMillis()); final boolean nowCached = app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ; if (nowCached != wasCached) { @@ -14011,7 +14011,8 @@ public final class ActivityManagerService extends ActivityManagerNative final void updateOomAdjLocked() { final ActivityRecord TOP_ACT = resumedAppLocked(); final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; - final long oldTime = SystemClock.uptimeMillis() - ProcessList.MAX_EMPTY_TIME; + final long now = SystemClock.uptimeMillis(); + final long oldTime = now - ProcessList.MAX_EMPTY_TIME; if (false) { RuntimeException e = new RuntimeException(); @@ -14040,7 +14041,7 @@ public final class ActivityManagerService extends ActivityManagerNative // them. int numSlots = (ProcessList.CACHED_APP_MAX_ADJ - ProcessList.CACHED_APP_MIN_ADJ + 1) / 2; - int numEmptyProcs = mLruProcesses.size()- mNumNonCachedProcs - mNumCachedProcs; + int numEmptyProcs = mLruProcesses.size()- mNumNonCachedProcs - mNumCachedHiddenProcs; if (numEmptyProcs > cachedProcessLimit) { // If there are more empty processes than our limit on cached // processes, then use the cached process limit for the factor. @@ -14052,7 +14053,7 @@ public final class ActivityManagerService extends ActivityManagerNative } int emptyFactor = numEmptyProcs/numSlots; if (emptyFactor < 1) emptyFactor = 1; - int cachedFactor = (mNumCachedProcs > 0 ? mNumCachedProcs : 1)/numSlots; + int cachedFactor = (mNumCachedHiddenProcs > 0 ? mNumCachedHiddenProcs : 1)/numSlots; if (cachedFactor < 1) cachedFactor = 1; int stepCached = 0; int stepEmpty = 0; @@ -14061,7 +14062,7 @@ public final class ActivityManagerService extends ActivityManagerNative int numTrimming = 0; mNumNonCachedProcs = 0; - mNumCachedProcs = 0; + mNumCachedHiddenProcs = 0; // First update the OOM adjustment for each of the // application processes based on their current state. @@ -14071,16 +14072,20 @@ public final class ActivityManagerService extends ActivityManagerNative int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ; int nextEmptyAdj = curEmptyAdj+2; int curClientCachedAdj = curEmptyAdj; + boolean changed = false; while (i > 0) { i--; ProcessRecord app = mLruProcesses.get(i); //Slog.i(TAG, "OOM " + app + ": cur cached=" + curCachedAdj); - updateOomAdjLocked(app, curCachedAdj, curClientCachedAdj, curEmptyAdj, TOP_APP, true); + app.setAdjChanged = false; + updateOomAdjLocked(app, curCachedAdj, curClientCachedAdj, curEmptyAdj, TOP_APP, + true, now); + changed |= app.setAdjChanged; if (!app.killedBackground) { if (app.curRawAdj == curCachedAdj && app.hasActivities) { // This process was assigned as a cached process... step the // cached level. - mNumCachedProcs++; + mNumCachedHiddenProcs++; if (curCachedAdj != nextCachedAdj) { stepCached++; if (stepCached >= cachedFactor) { @@ -14188,6 +14193,7 @@ 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. + int memFactor = ProcessTracker.STATE_MEM_FACTOR_NORMAL_ADJ; if (numCached <= ProcessList.TRIM_CACHED_APPS && numEmpty <= ProcessList.TRIM_EMPTY_APPS) { final int numCachedAndEmpty = numCached + numEmpty; @@ -14201,10 +14207,13 @@ public final class ActivityManagerService extends ActivityManagerNative int fgTrimLevel; if (numCachedAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) { fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL; + memFactor = ProcessTracker.STATE_MEM_FACTOR_CRITIAL_ADJ; } else if (numCachedAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) { fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW; + memFactor = ProcessTracker.STATE_MEM_FACTOR_LOW_ADJ; } else { fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE; + memFactor = ProcessTracker.STATE_MEM_FACTOR_MODERATE_ADJ; } int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE; for (i=0; i<N; i++) { @@ -14303,6 +14312,21 @@ public final class ActivityManagerService extends ActivityManagerNative // be in a consistent state at this point. mStackSupervisor.scheduleDestroyAllActivities(null, "always-finish"); } + + boolean allChanged = mProcessTracker.setMemFactor(memFactor, !mSleeping, now); + if (changed || allChanged) { + memFactor = mProcessTracker.getMemFactor(); + for (i=mLruProcesses.size()-1; i>=0; i--) { + ProcessRecord app = mLruProcesses.get(i); + if (allChanged || app.setAdjChanged) { + app.setProcessTrackerState(TOP_APP, memFactor, now, mProcessList); + } + } + } + + if (DEBUG_OOM_ADJ) { + Slog.d(TAG, "Did OOM ADJ in " + (SystemClock.uptimeMillis()-now) + "ms"); + } } final void trimApplications() { diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java index 6fe28f4..ba8de39 100644 --- a/services/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/java/com/android/server/am/ActivityStackSupervisor.java @@ -987,7 +987,7 @@ public final class ActivityStackSupervisor { if (app != null && app.thread != null) { try { - app.addPackage(r.info.packageName); + app.addPackage(r.info.packageName, mService.mProcessTracker); realStartActivityLocked(r, app, andResume, checkConfig); return; } catch (RemoteException e) { diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java index c7e6010..0e7513c 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/java/com/android/server/am/BroadcastQueue.java @@ -795,7 +795,7 @@ public final class BroadcastQueue { info.activityInfo.applicationInfo.uid); if (app != null && app.thread != null) { try { - app.addPackage(info.activityInfo.packageName); + app.addPackage(info.activityInfo.packageName, mService.mProcessTracker); processCurBroadcastLocked(r, app); return; } catch (RemoteException e) { diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java index f56371c..59e6787 100644 --- a/services/java/com/android/server/am/CompatModePackages.java +++ b/services/java/com/android/server/am/CompatModePackages.java @@ -300,7 +300,7 @@ public final class CompatModePackages { // Tell all processes that loaded this package about the change. for (int i=mService.mLruProcesses.size()-1; i>=0; i--) { ProcessRecord app = mService.mLruProcesses.get(i); - if (!app.pkgList.contains(packageName)) { + if (!app.pkgList.containsKey(packageName)) { continue; } try { diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java index e937d35..b5d783d 100644 --- a/services/java/com/android/server/am/ProcessList.java +++ b/services/java/com/android/server/am/ProcessList.java @@ -244,7 +244,7 @@ final class ProcessList { } int adjToTrackedState(int adj) { - return mAdjToTrackedState[adj]; + return adj >= FOREGROUND_APP_ADJ ? mAdjToTrackedState[adj] : ProcessTracker.STATE_NOTHING; } private void writeFile(String path, String data) { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 6cae67c..cc0a5a3 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -51,9 +51,10 @@ final class ProcessRecord { 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 + final ProcessTracker.ProcessState baseProcessTracker; // List of packages running in the process - final HashSet<String> pkgList = new HashSet<String>(); + final ArrayMap<String, ProcessTracker.ProcessState> pkgList + = new ArrayMap<String, ProcessTracker.ProcessState>(); IApplicationThread thread; // the actual proc... may be null only if // 'persistent' is true (in which case we // are in the process of launching the app) @@ -87,6 +88,7 @@ final class ProcessRecord { boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower boolean bad; // True if disabled in the bad process list boolean killedBackground; // True when proc has been killed due to too many bg + boolean setAdjChanged; // Keep track of whether we changed 'setAdj'. String waitingToKill; // Process is waiting to be killed when in the bg; reason IBinder forcingToForeground;// Token that is forcing this process to be foreground int adjSeq; // Sequence id for identifying oom_adj assignment cycles @@ -327,15 +329,15 @@ final class ProcessRecord { ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, IApplicationThread _thread, ApplicationInfo _info, String _processName, int _uid, - ProcessTracker.ProcessState _tracker) { + 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); + baseProcessTracker = tracker; + pkgList.put(_info.packageName, tracker); thread = _thread; maxAdj = ProcessList.CACHED_APP_MAX_ADJ; cachedAdj = clientCachedAdj = emptyAdj = ProcessList.CACHED_APP_MIN_ADJ; @@ -437,20 +439,33 @@ final class ProcessRecord { /* * Return true if package has been added false if not */ - public boolean addPackage(String pkg) { - if (!pkgList.contains(pkg)) { - pkgList.add(pkg); + public boolean addPackage(String pkg, ProcessTracker tracker) { + if (!pkgList.containsKey(pkg)) { + pkgList.put(pkg, tracker.getProcessStateLocked(pkg, info.uid, processName)); return true; } return false; } - + + public void setProcessTrackerState(ProcessRecord TOP_APP, int memFactor, long now, + ProcessList plist) { + int state = this == TOP_APP ? ProcessTracker.STATE_TOP + : plist.adjToTrackedState(setAdj); + for (int ip=pkgList.size()-1; ip>=0; ip--) { + pkgList.valueAt(ip).setState(state, memFactor, now); + } + } + /* * Delete all packages from list except the package indicated in info */ public void resetPackageList() { + long now = SystemClock.uptimeMillis(); + for (int i=0; i<pkgList.size(); i++) { + pkgList.valueAt(i).setState(ProcessTracker.STATE_NOTHING, 0, now); + } pkgList.clear(); - pkgList.add(info.packageName); + pkgList.put(info.packageName, baseProcessTracker); } public String[] getPackageList() { @@ -459,7 +474,9 @@ final class ProcessRecord { return null; } String list[] = new String[size]; - pkgList.toArray(list); + for (int i=0; i<pkgList.size(); i++) { + list[i] = pkgList.keyAt(i); + } return list; } } diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java index 4eb71c7..fb8d09c 100644 --- a/services/java/com/android/server/am/ProcessTracker.java +++ b/services/java/com/android/server/am/ProcessTracker.java @@ -36,7 +36,15 @@ public final class ProcessTracker { 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_MEM_FACTOR_MOD = STATE_CACHED+1; + public static final int STATE_MEM_FACTOR_NORMAL_ADJ = 0; + public static final int STATE_MEM_FACTOR_MODERATE_ADJ = STATE_MEM_FACTOR_MOD; + public static final int STATE_MEM_FACTOR_LOW_ADJ = STATE_MEM_FACTOR_MOD*2; + public static final int STATE_MEM_FACTOR_CRITIAL_ADJ = STATE_MEM_FACTOR_MOD*3; + public static final int STATE_MEM_FACTOR_COUNT = STATE_MEM_FACTOR_MOD*4; + public static final int STATE_SCREEN_ON_MOD = STATE_MEM_FACTOR_COUNT; + public static final int STATE_SCREEN_OFF_ADJ = 0; + public static final int STATE_SCREEN_ON_ADJ = STATE_SCREEN_ON_MOD; public static final int STATE_COUNT = STATE_SCREEN_ON_MOD*2; static String[] STATE_NAMES = new String[] { @@ -45,21 +53,44 @@ public final class ProcessTracker { }; public static final class ProcessState { - final long[] mTimes = new long[STATE_COUNT]; + final long[] mDurations = 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; + public void setState(int state, int memFactor, long now) { + if (state != STATE_NOTHING) { + state += memFactor; + } + if (mCurState != state) { + if (mCurState != STATE_NOTHING) { + mDurations[mCurState] += now - mStartTime; + } + mCurState = state; + mStartTime = now; } - mCurState = state; - mStartTime = now; + } + } + + public static final class ServiceState { + long mStartedDuration; + long mStartedTime; + } + + public static final class PackageState { + final ArrayMap<String, ProcessState> mProcesses = new ArrayMap<String, ProcessState>(); + final ArrayMap<String, ServiceState> mServices = new ArrayMap<String, ServiceState>(); + final int mUid; + + public PackageState(int uid) { + mUid = uid; } } static final class State { - final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>(); + final ProcessMap<PackageState> mPackages = new ProcessMap<PackageState>(); + final long[] mMemFactorDurations = new long[STATE_COUNT/STATE_MEM_FACTOR_MOD]; + int mMemFactor = STATE_NOTHING; + long mStartTime; } final State mState = new State(); @@ -67,44 +98,198 @@ public final class ProcessTracker { public ProcessTracker() { } - public ProcessState getStateLocked(String name, int uid) { - ProcessState ps = mState.mProcesses.get(name, uid); + private PackageState getPackageStateLocked(String packageName, int uid) { + PackageState as = mState.mPackages.get(packageName, uid); + if (as != null) { + return as; + } + as = new PackageState(uid); + mState.mPackages.put(packageName, uid, as); + return as; + } + + public ProcessState getProcessStateLocked(String packageName, int uid, String processName) { + final PackageState as = getPackageStateLocked(packageName, uid); + ProcessState ps = as.mProcesses.get(processName); if (ps != null) { return ps; } ps = new ProcessState(); - mState.mProcesses.put(name, uid, ps); + as.mProcesses.put(processName, ps); return ps; } + public ServiceState getServiceStateLocked(String packageName, int uid, String className) { + final PackageState as = getPackageStateLocked(packageName, uid); + ServiceState ss = as.mServices.get(className); + if (ss != null) { + return ss; + } + ss = new ServiceState(); + as.mServices.put(className, ss); + return ss; + } + + public boolean setMemFactor(int memFactor, boolean screenOn, long now) { + if (screenOn) { + memFactor += STATE_SCREEN_ON_MOD; + } + if (memFactor != mState.mMemFactor) { + if (mState.mMemFactor != STATE_NOTHING) { + mState.mMemFactorDurations[mState.mMemFactor/STATE_MEM_FACTOR_MOD] + += now - mState.mStartTime; + } + mState.mMemFactor = memFactor; + mState.mStartTime = now; + return true; + } + return false; + } + + public int getMemFactor() { + return mState.mMemFactor != STATE_NOTHING ? mState.mMemFactor : 0; + } + + private void printScreenLabel(PrintWriter pw, int offset) { + switch (offset) { + case STATE_NOTHING: + pw.print(" "); + break; + case STATE_SCREEN_OFF_ADJ: + pw.print("Screen Off / "); + break; + case STATE_SCREEN_ON_ADJ: + pw.print("Screen On / "); + break; + default: + pw.print("?????????? / "); + break; + } + } + + private void printMemLabel(PrintWriter pw, int offset) { + switch (offset) { + case STATE_NOTHING: + pw.print(" "); + break; + case STATE_MEM_FACTOR_NORMAL_ADJ: + pw.print("Norm / "); + break; + case STATE_MEM_FACTOR_MODERATE_ADJ: + pw.print("Mod / "); + break; + case STATE_MEM_FACTOR_LOW_ADJ: + pw.print("Low / "); + break; + case STATE_MEM_FACTOR_CRITIAL_ADJ: + pw.print("Crit / "); + break; + default: + pw.print("???? / "); + break; + } + } + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { final long now = SystemClock.uptimeMillis(); - ArrayMap<String, SparseArray<ProcessState>> pmap = mState.mProcesses.getMap(); + ArrayMap<String, SparseArray<PackageState>> pmap = mState.mPackages.getMap(); + pw.println("Process Stats:"); for (int ip=0; ip<pmap.size(); ip++) { String procName = pmap.keyAt(ip); - SparseArray<ProcessState> procs = pmap.valueAt(ip); + SparseArray<PackageState> procs = pmap.valueAt(ip); for (int iu=0; iu<procs.size(); iu++) { int uid = procs.keyAt(iu); - ProcessState state = procs.valueAt(iu); + PackageState 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; + for (int iproc=0; iproc<state.mProcesses.size(); iproc++) { + pw.print(" Process "); + pw.print(state.mProcesses.keyAt(iproc)); + pw.println(":"); + long totalTime = 0; + ProcessState proc = state.mProcesses.valueAt(iproc); + int printedScreen = -1; + for (int iscreen=0; iscreen<STATE_COUNT; iscreen+=STATE_SCREEN_ON_MOD) { + int printedMem = -1; + for (int imem=0; imem<STATE_MEM_FACTOR_COUNT; imem+=STATE_MEM_FACTOR_MOD) { + for (int is=0; is<STATE_NAMES.length; is++) { + int bucket = is+imem+iscreen; + long time = proc.mDurations[bucket]; + String running = ""; + if (proc.mCurState == bucket) { + time += now - proc.mStartTime; + running = " (running)"; + } + if (time != 0) { + pw.print(" "); + printScreenLabel(pw, printedScreen != iscreen + ? iscreen : STATE_NOTHING); + printedScreen = iscreen; + printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING); + printedMem = imem; + pw.print(STATE_NAMES[is]); pw.print(": "); + TimeUtils.formatDuration(time, pw); pw.println(running); + totalTime += time; + } + } + } + } + if (totalTime != 0) { + pw.print(" "); + printScreenLabel(pw, STATE_NOTHING); + printMemLabel(pw, STATE_NOTHING); + pw.print("TOTAL : "); + TimeUtils.formatDuration(totalTime, pw); + pw.println(); + } + } + for (int isvc=0; isvc<state.mServices.size(); isvc++) { + pw.print(" Service "); + pw.print(state.mServices.keyAt(isvc)); + pw.println(":"); + ServiceState svc = state.mServices.valueAt(isvc); + long time = svc.mStartedDuration; + if (svc.mStartedTime >= 0) { + time += now - svc.mStartedTime; } if (time != 0) { - pw.print(" "); pw.print(STATE_NAMES[is]); pw.print(": "); + pw.print(" Started: "); TimeUtils.formatDuration(time, pw); pw.println(); - totalTime += time; } } - if (totalTime != 0) { - pw.print(" TOTAL : "); - TimeUtils.formatDuration(totalTime, pw); - pw.println(); + } + } + pw.println(); + pw.println("Run time Stats:"); + long totalTime = 0; + int printedScreen = -1; + for (int iscreen=0; iscreen<STATE_COUNT; iscreen+=STATE_SCREEN_ON_MOD) { + int printedMem = -1; + for (int imem=0; imem<STATE_MEM_FACTOR_COUNT; imem+=STATE_MEM_FACTOR_MOD) { + int bucket = imem+iscreen; + long time = mState.mMemFactorDurations[bucket/STATE_MEM_FACTOR_MOD]; + String running = ""; + if (mState.mMemFactor == bucket) { + time += now - mState.mStartTime; + running = " (running)"; + } + if (time != 0) { + pw.print(" "); + printScreenLabel(pw, printedScreen != iscreen + ? iscreen : STATE_NOTHING); + printedScreen = iscreen; + printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING); + printedMem = imem; + TimeUtils.formatDuration(time, pw); pw.println(running); + totalTime += time; } } } + if (totalTime != 0) { + pw.print(" "); + printScreenLabel(pw, STATE_NOTHING); + pw.print("TOTAL: "); + TimeUtils.formatDuration(totalTime, pw); + pw.println(); + } } } diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java index 4a3699c..82e8c7f 100644 --- a/services/java/com/android/server/wm/DisplayContent.java +++ b/services/java/com/android/server/wm/DisplayContent.java @@ -28,7 +28,6 @@ import android.util.Slog; import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; -import android.view.InputChannel; import java.io.PrintWriter; import java.util.ArrayList; @@ -101,11 +100,8 @@ class DisplayContent { /** Sorted most recent at top, oldest at [0]. */ ArrayList<TaskStack> mStackHistory = new ArrayList<TaskStack>(); - /** Forward motion events to mTapDetector. */ - InputChannel mTapInputChannel; - /** Detect user tapping outside of current focused stack bounds .*/ - StackTapDetector mTapDetector; + StackTapPointerEventListener mTapDetector; /** Detect user tapping outside of current focused stack bounds .*/ Region mTouchExcludeRegion = new Region(); diff --git a/services/java/com/android/server/wm/PointerEventDispatcher.java b/services/java/com/android/server/wm/PointerEventDispatcher.java new file mode 100644 index 0000000..6b0e4c9 --- /dev/null +++ b/services/java/com/android/server/wm/PointerEventDispatcher.java @@ -0,0 +1,90 @@ +/* + * 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.wm; + +import android.view.InputChannel; +import android.view.InputDevice; +import android.view.InputEvent; +import android.view.InputEventReceiver; +import android.view.MotionEvent; +import android.view.WindowManagerPolicy.PointerEventListener; + +import com.android.server.UiThread; + +import java.util.ArrayList; + +public class PointerEventDispatcher extends InputEventReceiver { + ArrayList<PointerEventListener> mListeners = new ArrayList<PointerEventListener>(); + PointerEventListener[] mListenersArray = new PointerEventListener[0]; + + public PointerEventDispatcher(InputChannel inputChannel) { + super(inputChannel, UiThread.getHandler().getLooper()); + } + + @Override + public void onInputEvent(InputEvent event) { + try { + if (event instanceof MotionEvent + && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + final MotionEvent motionEvent = (MotionEvent)event; + PointerEventListener[] listeners; + synchronized (mListeners) { + if (mListenersArray == null) { + mListenersArray = new PointerEventListener[mListeners.size()]; + mListeners.toArray(mListenersArray); + } + listeners = mListenersArray; + } + for (int i = 0; i < listeners.length; ++i) { + listeners[i].onPointerEvent(motionEvent); + } + } + } finally { + finishInputEvent(event, false); + } + } + + /** + * Add the specified listener to the list. + * @param listener The listener to add. + */ + public void registerInputEventListener(PointerEventListener listener) { + synchronized (mListeners) { + if (mListeners.contains(listener)) { + throw new IllegalStateException("registerInputEventListener: trying to register" + + listener + " twice."); + } + mListeners.add(listener); + mListenersArray = null; + } + } + + /** + * Remove the specified listener from the list. + * @param listener The listener to remove. + */ + public void unregisterInputEventListener(PointerEventListener listener) { + synchronized (mListeners) { + if (!mListeners.contains(listener)) { + throw new IllegalStateException("registerInputEventListener: " + listener + + " not registered."); + } + mListeners.remove(listener); + mListenersArray = null; + } + } +} diff --git a/services/java/com/android/server/wm/StackTapDetector.java b/services/java/com/android/server/wm/StackTapDetector.java deleted file mode 100644 index 7127fd2..0000000 --- a/services/java/com/android/server/wm/StackTapDetector.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.wm; - -import android.graphics.Region; -import android.os.Looper; -import android.view.DisplayInfo; -import android.view.InputChannel; -import android.view.InputDevice; -import android.view.InputEvent; -import android.view.InputEventReceiver; -import android.view.MotionEvent; - -import com.android.server.wm.WindowManagerService.H; - -public class StackTapDetector extends InputEventReceiver { - private static final int TAP_TIMEOUT_MSEC = 300; - private static final float TAP_MOTION_SLOP_INCHES = 0.125f; - - private final int mMotionSlop; - private float mDownX; - private float mDownY; - private int mPointerId; - final private Region mTouchExcludeRegion; - private final WindowManagerService mService; - private final DisplayContent mDisplayContent; - - public StackTapDetector(WindowManagerService service, DisplayContent displayContent, - InputChannel inputChannel, Looper looper) { - super(inputChannel, looper); - mService = service; - mDisplayContent = displayContent; - mTouchExcludeRegion = displayContent.mTouchExcludeRegion; - DisplayInfo info = displayContent.getDisplayInfo(); - mMotionSlop = (int)(info.logicalDensityDpi * TAP_MOTION_SLOP_INCHES); - } - - @Override - public void onInputEvent(InputEvent event) { - try { - if (!(event instanceof MotionEvent) - || !event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { - return; - } - final MotionEvent motionEvent = (MotionEvent)event; - final int action = motionEvent.getAction(); - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: - mPointerId = motionEvent.getPointerId(0); - mDownX = motionEvent.getX(); - mDownY = motionEvent.getY(); - break; - case MotionEvent.ACTION_MOVE: - if (mPointerId >= 0) { - int index = motionEvent.findPointerIndex(mPointerId); - if ((motionEvent.getEventTime() - motionEvent.getDownTime()) - > TAP_TIMEOUT_MSEC - || (motionEvent.getX(index) - mDownX) > mMotionSlop - || (motionEvent.getY(index) - mDownY) > mMotionSlop) { - mPointerId = -1; - } - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: { - int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - // Extract the index of the pointer that left the touch sensor - if (mPointerId == motionEvent.getPointerId(index)) { - final int x = (int)motionEvent.getX(index); - final int y = (int)motionEvent.getY(index); - synchronized (this) { - if ((motionEvent.getEventTime() - motionEvent.getDownTime()) - < TAP_TIMEOUT_MSEC - && (x - mDownX) < mMotionSlop && (y - mDownY) < mMotionSlop - && !mTouchExcludeRegion.contains(x, y)) { - mService.mH.obtainMessage(H.TAP_OUTSIDE_STACK, x, y, - mDisplayContent).sendToTarget(); - } - } - mPointerId = -1; - } - break; - } - } - } finally { - finishInputEvent(event, false /*ignored for monitors*/); - } - } -} diff --git a/services/java/com/android/server/wm/StackTapPointerEventListener.java b/services/java/com/android/server/wm/StackTapPointerEventListener.java new file mode 100644 index 0000000..19d8ab3 --- /dev/null +++ b/services/java/com/android/server/wm/StackTapPointerEventListener.java @@ -0,0 +1,87 @@ +/* + * 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.wm; + +import android.graphics.Region; +import android.view.DisplayInfo; +import android.view.MotionEvent; +import android.view.WindowManagerPolicy.PointerEventListener; + +import com.android.server.wm.WindowManagerService.H; + +public class StackTapPointerEventListener implements PointerEventListener { + private static final int TAP_TIMEOUT_MSEC = 300; + private static final float TAP_MOTION_SLOP_INCHES = 0.125f; + + private final int mMotionSlop; + private float mDownX; + private float mDownY; + private int mPointerId; + final private Region mTouchExcludeRegion; + private final WindowManagerService mService; + private final DisplayContent mDisplayContent; + + public StackTapPointerEventListener(WindowManagerService service, + DisplayContent displayContent) { + mService = service; + mDisplayContent = displayContent; + mTouchExcludeRegion = displayContent.mTouchExcludeRegion; + DisplayInfo info = displayContent.getDisplayInfo(); + mMotionSlop = (int)(info.logicalDensityDpi * TAP_MOTION_SLOP_INCHES); + } + + @Override + public void onPointerEvent(MotionEvent motionEvent) { + final int action = motionEvent.getAction(); + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: + mPointerId = motionEvent.getPointerId(0); + mDownX = motionEvent.getX(); + mDownY = motionEvent.getY(); + break; + case MotionEvent.ACTION_MOVE: + if (mPointerId >= 0) { + int index = motionEvent.findPointerIndex(mPointerId); + if ((motionEvent.getEventTime() - motionEvent.getDownTime()) > TAP_TIMEOUT_MSEC + || (motionEvent.getX(index) - mDownX) > mMotionSlop + || (motionEvent.getY(index) - mDownY) > mMotionSlop) { + mPointerId = -1; + } + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: { + int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; + // Extract the index of the pointer that left the touch sensor + if (mPointerId == motionEvent.getPointerId(index)) { + final int x = (int)motionEvent.getX(index); + final int y = (int)motionEvent.getY(index); + if ((motionEvent.getEventTime() - motionEvent.getDownTime()) + < TAP_TIMEOUT_MSEC + && (x - mDownX) < mMotionSlop && (y - mDownY) < mMotionSlop + && !mTouchExcludeRegion.contains(x, y)) { + mService.mH.obtainMessage(H.TAP_OUTSIDE_STACK, x, y, + mDisplayContent).sendToTarget(); + } + mPointerId = -1; + } + break; + } + } + } +} diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index f166c31..079134b 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -124,6 +124,7 @@ import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicy; import android.view.WindowManager.LayoutParams; import android.view.WindowManagerPolicy.FakeWindow; +import android.view.WindowManagerPolicy.PointerEventListener; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; @@ -281,8 +282,6 @@ public class WindowManagerService extends IWindowManager.Stub private static final String SYSTEM_SECURE = "ro.secure"; private static final String SYSTEM_DEBUGGABLE = "ro.debuggable"; - private static final String TAP_INPUT_CHANNEL_NAME = "StackTapDetector"; - private static final int MAX_SCREENSHOT_RETRIES = 3; final private KeyguardDisableHandler mKeyguardDisableHandler; @@ -594,6 +593,8 @@ public class WindowManagerService extends IWindowManager.Stub SparseArray<Task> mTaskIdToTask = new SparseArray<Task>(); SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>(); + private final PointerEventDispatcher mPointerEventDispatcher; + final class DragInputEventReceiver extends InputEventReceiver { public DragInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); @@ -728,6 +729,8 @@ public class WindowManagerService extends IWindowManager.Stub mDisplaySettings = new DisplaySettings(context); mDisplaySettings.readSettingsLocked(); + mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG)); + mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); mDisplayManager.registerDisplayListener(this, null); Display[] displays = mDisplayManager.getDisplays(); @@ -5098,6 +5101,16 @@ public class WindowManagerService extends IWindowManager.Stub mAnimatorDurationScale }; } + @Override + public void registerPointerEventListener(PointerEventListener listener) { + mPointerEventDispatcher.registerInputEventListener(listener); + } + + @Override + public void unregisterPointerEventListener(PointerEventListener listener) { + mPointerEventDispatcher.unregisterInputEventListener(listener); + } + // Called by window manager policy. Not exposed externally. @Override public int getLidState() { @@ -5117,12 +5130,6 @@ public class WindowManagerService extends IWindowManager.Stub // Called by window manager policy. Not exposed externally. @Override - public InputChannel monitorInput(String inputChannelName) { - return mInputManager.monitorInput(inputChannelName); - } - - // Called by window manager policy. Not exposed externally. - @Override public void switchKeyboardLayout(int deviceId, int direction) { mInputManager.switchKeyboardLayout(deviceId, direction); } @@ -10652,10 +10659,8 @@ public class WindowManagerService extends IWindowManager.Stub // TODO: Create an input channel for each display with touch capability. if (displayId == Display.DEFAULT_DISPLAY) { - InputChannel inputChannel = monitorInput(TAP_INPUT_CHANNEL_NAME); - displayContent.mTapInputChannel = inputChannel; - displayContent.mTapDetector = - new StackTapDetector(this, displayContent, inputChannel, Looper.myLooper()); + displayContent.mTapDetector = new StackTapPointerEventListener(this, displayContent); + registerPointerEventListener(displayContent.mTapDetector); } return displayContent; @@ -10838,10 +10843,9 @@ public class WindowManagerService extends IWindowManager.Stub if (displayContent != null) { mDisplayContents.delete(displayId); - if (displayContent.mTapInputChannel != null) { - displayContent.mTapInputChannel.dispose(); + if (displayId == Display.DEFAULT_DISPLAY) { + unregisterPointerEventListener(displayContent.mTapDetector); } - WindowList windows = displayContent.getWindowList(); while (!windows.isEmpty()) { final WindowState win = windows.get(windows.size() - 1); |
