diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 43135334ba74f..a5615a9c56fe3 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -166,8 +166,11 @@ public final class ActiveServices { */ static final class ActiveForegroundApp { String mPackageName; + int mUid; CharSequence mLabel; boolean mShownWhileScreenOn; + boolean mAppOnTop; + boolean mShownWhileTop; long mStartTime; long mStartVisibleTime; long mEndTime; @@ -728,11 +731,12 @@ public final class ActiveServices { synchronized (mAm) { final long now = SystemClock.elapsedRealtime(); final long nowPlusMin = now + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME; + long nextUpdateTime = Long.MAX_VALUE; if (smap != null) { for (int i = smap.mActiveForegroundApps.size()-1; i >= 0; i--) { ActiveForegroundApp aa = smap.mActiveForegroundApps.valueAt(i); if (aa.mEndTime != 0 && (mScreenOn || aa.mShownWhileScreenOn)) { - if (aa.mEndTime < (aa.mStartVisibleTime + if (!aa.mShownWhileTop && aa.mEndTime < (aa.mStartVisibleTime + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) { // Check to see if this should still be displayed... we continue // until it has been shown for at least the timeout duration. @@ -741,6 +745,12 @@ public final class ActiveServices { smap.mActiveForegroundApps.removeAt(i); smap.mActiveForegroundAppsChanged = true; continue; + } else { + long hideTime = aa.mStartVisibleTime + + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME; + if (hideTime < nextUpdateTime) { + nextUpdateTime = hideTime; + } } } else { // This was up for longer than the timeout, so just remove immediately. @@ -749,10 +759,17 @@ public final class ActiveServices { continue; } } - if (active == null) { - active = new ArrayList<>(); + if (!aa.mAppOnTop) { + if (active == null) { + active = new ArrayList<>(); + } + active.add(aa); } - active.add(aa); + } + smap.removeMessages(ServiceMap.MSG_UPDATE_FOREGROUND_APPS); + if (nextUpdateTime < Long.MAX_VALUE) { + Message msg = smap.obtainMessage(); + smap.sendMessageAtTime(msg, nextUpdateTime); } } if (!smap.mActiveForegroundAppsChanged) { @@ -842,7 +859,7 @@ public final class ActiveServices { active.mNumActive--; if (active.mNumActive <= 0) { active.mEndTime = SystemClock.elapsedRealtime(); - if (active.mEndTime >= (active.mStartVisibleTime + if (active.mShownWhileTop || active.mEndTime >= (active.mStartVisibleTime + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) { // Have been active for long enough that we will remove it immediately. smap.mActiveForegroundApps.remove(r.packageName); @@ -887,6 +904,31 @@ public final class ActiveServices { } } + void foregroundServiceProcStateChangedLocked(UidRecord uidRec) { + ServiceMap smap = mServiceMap.get(UserHandle.getUserId(uidRec.uid)); + if (smap != null) { + boolean changed = false; + for (int j = smap.mActiveForegroundApps.size()-1; j >= 0; j--) { + ActiveForegroundApp active = smap.mActiveForegroundApps.valueAt(j); + if (active.mUid == uidRec.uid) { + if (uidRec.curProcState <= ActivityManager.PROCESS_STATE_TOP) { + if (!active.mAppOnTop) { + active.mAppOnTop = true; + changed = true; + } + active.mShownWhileTop = true; + } else if (active.mAppOnTop) { + active.mAppOnTop = false; + changed = true; + } + } + } + if (changed) { + requestUpdateActiveForegroundAppsLocked(smap, 0); + } + } + } + private void setServiceForegroundInnerLocked(ServiceRecord r, int id, Notification notification, int flags) { if (id != 0) { @@ -948,7 +990,13 @@ public final class ActiveServices { if (active == null) { active = new ActiveForegroundApp(); active.mPackageName = r.packageName; + active.mUid = r.appInfo.uid; active.mShownWhileScreenOn = mScreenOn; + if (r.app != null) { + active.mAppOnTop = active.mShownWhileTop = + r.app.uidRecord.curProcState + <= ActivityManager.PROCESS_STATE_TOP; + } active.mStartTime = active.mStartVisibleTime = SystemClock.elapsedRealtime(); smap.mActiveForegroundApps.put(r.packageName, active); @@ -2790,6 +2838,9 @@ public final class ActiveServices { if (!doit && didSomething) { return true; } + if (doit && filterByClasses == null) { + forceStopPackageLocked(packageName, mServiceMap.valueAt(i).mUserId); + } } } else { ServiceMap smap = mServiceMap.get(userId); @@ -2798,6 +2849,9 @@ public final class ActiveServices { didSomething = collectPackageServicesLocked(packageName, filterByClasses, evenPersistent, doit, killProcess, items); } + if (doit && filterByClasses == null) { + forceStopPackageLocked(packageName, userId); + } } if (mTmpCollectionResults != null) { @@ -2806,10 +2860,11 @@ public final class ActiveServices { } mTmpCollectionResults.clear(); } + return didSomething; } - void removeUninstalledPackageLocked(String packageName, int userId) { + void forceStopPackageLocked(String packageName, int userId) { ServiceMap smap = mServiceMap.get(userId); if (smap != null && smap.mActiveForegroundApps.size() > 0) { for (int i = smap.mActiveForegroundApps.size()-1; i >= 0; i--) { @@ -3640,6 +3695,10 @@ public final class ActiveServices { } pw.print(" mNumActive="); pw.print(aa.mNumActive); + pw.print(" mAppOnTop="); + pw.print(aa.mAppOnTop); + pw.print(" mShownWhileTop="); + pw.print(aa.mShownWhileTop); pw.print(" mShownWhileScreenOn="); pw.println(aa.mShownWhileScreenOn); pw.print(" mStartTime="); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6dcbe63a51def..c65aac4eb2d13 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -120,7 +120,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER; @@ -19007,7 +19006,7 @@ public class ActivityManagerService extends IActivityManager.Stub removeTasksByPackageNameLocked(ssp, userId); - mServices.removeUninstalledPackageLocked(ssp, userId); + mServices.forceStopPackageLocked(ssp, userId); // Hide the "unsupported display" dialog if necessary. if (mUnsupportedDisplaySizeDialog != null && ssp.equals( @@ -22278,6 +22277,9 @@ public class ActivityManagerService extends IActivityManager.Stub if (uidRec.curProcState > app.curProcState) { uidRec.curProcState = app.curProcState; } + if (app.foregroundServices) { + uidRec.foregroundServices = true; + } } } @@ -22519,6 +22521,9 @@ public class ActivityManagerService extends IActivityManager.Stub uidRec.setWhitelist = uidRec.curWhitelist; enqueueUidChangeLocked(uidRec, -1, uidChange); noteUidProcessState(uidRec.uid, uidRec.curProcState); + if (uidRec.foregroundServices) { + mServices.foregroundServiceProcStateChangedLocked(uidRec); + } } } if (mLocalPowerManager != null) { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index b025385413ead..fbc2bd270a750 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -103,7 +103,6 @@ final class ProcessRecord { int renderThreadTid; // TID for RenderThread boolean serviceb; // Process currently is on the service B list boolean serviceHighRam; // We are forcing to service B list due to its RAM use - boolean setIsForeground; // Running foreground UI when last set? boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle? boolean hasClientActivities; // Are there any client services with activities? boolean hasStartedServices; // Are there any started services running in this process? @@ -303,9 +302,8 @@ final class ProcessRecord { pw.print(" hasAboveClient="); pw.print(hasAboveClient); pw.print(" treatLikeActivity="); pw.println(treatLikeActivity); } - if (setIsForeground || foregroundServices || forcingToForeground != null) { - pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground); - pw.print(" foregroundServices="); pw.print(foregroundServices); + if (foregroundServices || forcingToForeground != null) { + pw.print(prefix); pw.print("foregroundServices="); pw.print(foregroundServices); pw.print(" forcingToForeground="); pw.println(forcingToForeground); } if (reportedInteraction || fgInteractionTime != 0) { diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java index c0fb77f086472..c411bcec45400 100644 --- a/services/core/java/com/android/server/am/UidRecord.java +++ b/services/core/java/com/android/server/am/UidRecord.java @@ -35,6 +35,7 @@ public final class UidRecord { int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT; long lastBackgroundTime; boolean ephemeral; + boolean foregroundServices; boolean curWhitelist; boolean setWhitelist; boolean idle; @@ -102,6 +103,7 @@ public final class UidRecord { public void reset() { curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; + foregroundServices = false; } public void updateHasInternetPermission() { @@ -131,6 +133,9 @@ public final class UidRecord { if (ephemeral) { sb.append(" ephemeral"); } + if (foregroundServices) { + sb.append(" fgServices"); + } if (curWhitelist) { sb.append(" whitelist"); }