diff options
| author | 2017-06-15 18:45:28 +0000 | |
|---|---|---|
| committer | 2017-06-15 18:45:35 +0000 | |
| commit | ef0554438f11c9ea5d7bcd5bab5c97808b55dd43 (patch) | |
| tree | 2003065bb95d62df343ff80c869981ee4a1db947 | |
| parent | 04298759fe956ce712a84d7df049e14c1815cb07 (diff) | |
| parent | cb01563d7efa5689abb98fe4e5d8cc86bfc2b6fc (diff) | |
Merge "Work on issue #36891897: Need to ensure foreground services..." into oc-dev
| -rw-r--r-- | core/java/android/os/Handler.java | 20 | ||||
| -rw-r--r-- | core/java/android/os/Looper.java | 15 | ||||
| -rw-r--r-- | core/java/android/os/MessageQueue.java | 23 | ||||
| -rwxr-xr-x | core/java/android/provider/Settings.java | 5 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActiveServices.java | 144 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerConstants.java | 57 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerDebugConfig.java | 1 |
7 files changed, 216 insertions, 49 deletions
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index 8678d95db17d..b69a23aa5854 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -696,6 +696,14 @@ public class Handler { } /** + * Return whether there are any messages or callbacks currently scheduled on this handler. + * @hide + */ + public final boolean hasMessagesOrCallbacks() { + return mQueue.hasMessages(this); + } + + /** * Check if there are any pending posts of messages with code 'what' and * whose obj is 'object' in the message queue. */ @@ -728,6 +736,18 @@ public class Handler { } } + /** + * @hide + */ + public final void dumpMine(Printer pw, String prefix) { + pw.println(prefix + this + " @ " + SystemClock.uptimeMillis()); + if (mLooper == null) { + pw.println(prefix + "looper uninitialized"); + } else { + mLooper.dump(pw, prefix + " ", this); + } + } + @Override public String toString() { return "Handler (" + getClass().getName() + ") {" diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index 44dbcfb09582..04cceb8e80ba 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -310,7 +310,20 @@ public final class Looper { */ public void dump(@NonNull Printer pw, @NonNull String prefix) { pw.println(prefix + toString()); - mQueue.dump(pw, prefix + " "); + mQueue.dump(pw, prefix + " ", null); + } + + /** + * Dumps the state of the looper for debugging purposes. + * + * @param pw A printer to receive the contents of the dump. + * @param prefix A prefix to prepend to each line which is printed. + * @param handler Only dump messages for this Handler. + * @hide + */ + public void dump(@NonNull Printer pw, @NonNull String prefix, Handler handler) { + pw.println(prefix + toString()); + mQueue.dump(pw, prefix + " ", handler); } /** @hide */ diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java index 2a8c52e92c60..624e28a67ae6 100644 --- a/core/java/android/os/MessageQueue.java +++ b/core/java/android/os/MessageQueue.java @@ -620,6 +620,23 @@ public final class MessageQueue { } } + boolean hasMessages(Handler h) { + if (h == null) { + return false; + } + + synchronized (this) { + Message p = mMessages; + while (p != null) { + if (p.target == h) { + return true; + } + p = p.next; + } + return false; + } + } + void removeMessages(Handler h, int what, Object object) { if (h == null) { return; @@ -759,12 +776,14 @@ public final class MessageQueue { } } - void dump(Printer pw, String prefix) { + void dump(Printer pw, String prefix, Handler h) { synchronized (this) { long now = SystemClock.uptimeMillis(); int n = 0; for (Message msg = mMessages; msg != null; msg = msg.next) { - pw.println(prefix + "Message " + n + ": " + msg.toString(now)); + if (h == null || h == msg.target) { + pw.println(prefix + "Message " + n + ": " + msg.toString(now)); + } n++; } pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked() diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index f1ce9d52e920..65669ee70216 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9029,7 +9029,10 @@ public final class Settings { * <pre> * max_cached_processes (int) * background_settle_time (long) - * foreground_service_ui_min_time (long) + * fgservice_min_shown_time (long) + * fgservice_min_report_time (long) + * fgservice_screen_on_before_time (long) + * fgservice_screen_on_after_time (long) * content_provider_retain_time (long) * gc_timeout (long) * gc_min_interval (long) diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index c41748424b10..de144777e7c4 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -81,6 +81,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.util.EventLog; +import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; @@ -175,6 +176,9 @@ public final class ActiveServices { long mStartVisibleTime; long mEndTime; int mNumActive; + + // Temp output of foregroundAppShownEnoughLocked + long mHideTime; } /** @@ -736,50 +740,90 @@ public final class ActiveServices { } } + boolean foregroundAppShownEnoughLocked(ActiveForegroundApp aa, long nowElapsed) { + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Shown enough: pkg=" + aa.mPackageName + ", uid=" + + aa.mUid); + boolean canRemove = false; + aa.mHideTime = Long.MAX_VALUE; + if (aa.mShownWhileTop) { + // If the app was ever at the top of the screen while the foreground + // service was running, then we can always just immediately remove it. + canRemove = true; + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "YES - shown while on top"); + } else if (mScreenOn || aa.mShownWhileScreenOn) { + final long minTime = aa.mStartVisibleTime + + (aa.mStartTime != aa.mStartVisibleTime + ? mAm.mConstants.FGSERVICE_SCREEN_ON_AFTER_TIME + : mAm.mConstants.FGSERVICE_MIN_SHOWN_TIME); + if (nowElapsed >= minTime) { + // If shown while the screen is on, and it has been shown for + // at least the minimum show time, then we can now remove it. + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "YES - shown long enough with screen on"); + canRemove = true; + } else { + // This is when we will be okay to stop telling the user. + long reportTime = nowElapsed + mAm.mConstants.FGSERVICE_MIN_REPORT_TIME; + aa.mHideTime = reportTime > minTime ? reportTime : minTime; + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "NO -- wait " + (aa.mHideTime-nowElapsed) + + " with screen on"); + } + } else { + final long minTime = aa.mEndTime + + mAm.mConstants.FGSERVICE_SCREEN_ON_BEFORE_TIME; + if (nowElapsed >= minTime) { + // If the foreground service has only run while the screen is + // off, but it has been gone now for long enough that we won't + // care to tell the user about it when the screen comes back on, + // then we can remove it now. + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "YES - gone long enough with screen off"); + canRemove = true; + } else { + // This is when we won't care about this old fg service. + aa.mHideTime = minTime; + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "NO -- wait " + (aa.mHideTime-nowElapsed) + + " with screen off"); + } + } + return canRemove; + } + void updateForegroundApps(ServiceMap smap) { // This is called from the handler without the lock held. ArrayList<ActiveForegroundApp> active = null; 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) { + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Updating foreground apps for user " + + smap.mUserId); 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.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. - if (nowPlusMin >= aa.mStartVisibleTime) { - // All over! - 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 { + if (aa.mEndTime != 0) { + boolean canRemove = foregroundAppShownEnoughLocked(aa, now); + if (canRemove) { // This was up for longer than the timeout, so just remove immediately. smap.mActiveForegroundApps.removeAt(i); smap.mActiveForegroundAppsChanged = true; continue; } + if (aa.mHideTime < nextUpdateTime) { + nextUpdateTime = aa.mHideTime; + } } if (!aa.mAppOnTop) { if (active == null) { active = new ArrayList<>(); } + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Adding active: pkg=" + + aa.mPackageName + ", uid=" + aa.mUid); active.add(aa); } } smap.removeMessages(ServiceMap.MSG_UPDATE_FOREGROUND_APPS); if (nextUpdateTime < Long.MAX_VALUE) { - Message msg = smap.obtainMessage(); + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Next update time in: " + + (nextUpdateTime-now)); + Message msg = smap.obtainMessage(ServiceMap.MSG_UPDATE_FOREGROUND_APPS); smap.sendMessageAtTime(msg, nextUpdateTime + SystemClock.uptimeMillis() - SystemClock.elapsedRealtime()); } @@ -882,15 +926,14 @@ public final class ActiveServices { active.mNumActive--; if (active.mNumActive <= 0) { active.mEndTime = SystemClock.elapsedRealtime(); - if (active.mShownWhileTop || active.mEndTime >= (active.mStartVisibleTime - + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) { + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Ended running of service"); + if (foregroundAppShownEnoughLocked(active, active.mEndTime)) { // Have been active for long enough that we will remove it immediately. smap.mActiveForegroundApps.remove(r.packageName); smap.mActiveForegroundAppsChanged = true; requestUpdateActiveForegroundAppsLocked(smap, 0); - } else { - requestUpdateActiveForegroundAppsLocked(smap, active.mStartVisibleTime - + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME); + } else if (active.mHideTime < Long.MAX_VALUE){ + requestUpdateActiveForegroundAppsLocked(smap, active.mHideTime); } } } @@ -904,26 +947,44 @@ public final class ActiveServices { // services that were started while the screen was off. if (screenOn) { final long nowElapsed = SystemClock.elapsedRealtime(); + if (DEBUG_FOREGROUND_SERVICE) Slog.d(TAG, "Screen turned on"); for (int i = mServiceMap.size()-1; i >= 0; i--) { ServiceMap smap = mServiceMap.valueAt(i); + long nextUpdateTime = Long.MAX_VALUE; boolean changed = false; for (int j = smap.mActiveForegroundApps.size()-1; j >= 0; j--) { ActiveForegroundApp active = smap.mActiveForegroundApps.valueAt(j); - if (!active.mShownWhileScreenOn) { - changed = true; - active.mShownWhileScreenOn = mScreenOn; - active.mStartVisibleTime = nowElapsed; - if (active.mEndTime != 0) { - active.mEndTime = nowElapsed; + if (active.mEndTime == 0) { + if (!active.mShownWhileScreenOn) { + active.mShownWhileScreenOn = true; + active.mStartVisibleTime = nowElapsed; + } + } else { + if (!active.mShownWhileScreenOn + && active.mStartVisibleTime == active.mStartTime) { + // If this was never shown while the screen was on, then we will + // count the time it started being visible as now, to tell the user + // about it now that they have a screen to look at. + active.mEndTime = active.mStartVisibleTime = nowElapsed; + } + if (foregroundAppShownEnoughLocked(active, nowElapsed)) { + // Have been active for long enough that we will remove it + // immediately. + smap.mActiveForegroundApps.remove(active.mPackageName); + smap.mActiveForegroundAppsChanged = true; + changed = true; + } else { + if (active.mHideTime < nextUpdateTime) { + nextUpdateTime = active.mHideTime; + } } } } if (changed) { - requestUpdateActiveForegroundAppsLocked(smap, - nowElapsed + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME); - } else if (smap.mActiveForegroundApps.size() > 0) { - // Just being paranoid. + // Need to immediately update. requestUpdateActiveForegroundAppsLocked(smap, 0); + } else if (nextUpdateTime < Long.MAX_VALUE) { + requestUpdateActiveForegroundAppsLocked(smap, nextUpdateTime); } } } @@ -2318,7 +2379,7 @@ public final class ActiveServices { return true; } - // Is someone still bound to us keepign us running? + // Is someone still bound to us keeping us running? if (!knowConn) { hasConn = r.hasAutoCreateConnections(); } @@ -3741,6 +3802,17 @@ public final class ActiveServices { pw.println(); } } + if (smap.hasMessagesOrCallbacks()) { + if (needSep) { + pw.println(); + } + printedAnything = true; + needSep = true; + pw.print(" Handler - user "); + pw.print(user); + pw.println(":"); + smap.dumpMine(new PrintWriterPrinter(pw), " "); + } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 5749f31ddb2e..6c3fe915f386 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -35,8 +35,14 @@ final class ActivityManagerConstants extends ContentObserver { // Key names stored in the settings value. private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes"; private static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time"; - private static final String KEY_FOREGROUND_SERVICE_UI_MIN_TIME - = "foreground_service_ui_min_time"; + private static final String KEY_FGSERVICE_MIN_SHOWN_TIME + = "fgservice_min_shown_time"; + private static final String KEY_FGSERVICE_MIN_REPORT_TIME + = "fgservice_min_report_time"; + private static final String KEY_FGSERVICE_SCREEN_ON_BEFORE_TIME + = "fgservice_screen_on_before_time"; + private static final String KEY_FGSERVICE_SCREEN_ON_AFTER_TIME + = "fgservice_screen_on_after_time"; private static final String KEY_CONTENT_PROVIDER_RETAIN_TIME = "content_provider_retain_time"; private static final String KEY_GC_TIMEOUT = "gc_timeout"; private static final String KEY_GC_MIN_INTERVAL = "gc_min_interval"; @@ -58,7 +64,10 @@ final class ActivityManagerConstants extends ContentObserver { private static final int DEFAULT_MAX_CACHED_PROCESSES = 32; private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000; - private static final long DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME = 30*1000; + private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000; + private static final long DEFAULT_FGSERVICE_MIN_REPORT_TIME = 3*1000; + private static final long DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME = 1*1000; + private static final long DEFAULT_FGSERVICE_SCREEN_ON_AFTER_TIME = 5*1000; private static final long DEFAULT_CONTENT_PROVIDER_RETAIN_TIME = 20*1000; private static final long DEFAULT_GC_TIMEOUT = 5*1000; private static final long DEFAULT_GC_MIN_INTERVAL = 60*1000; @@ -85,8 +94,26 @@ final class ActivityManagerConstants extends ContentObserver { // before we start restricting what it can do. public long BACKGROUND_SETTLE_TIME = DEFAULT_BACKGROUND_SETTLE_TIME; - // The minimum time a foreground service will be shown as running in the notification UI. - public long FOREGROUND_SERVICE_UI_MIN_TIME = DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME; + // The minimum time we allow a foreground service to run with a notification and the + // screen on without otherwise telling the user about it. (If it runs for less than this, + // it will still be reported to the user as a running app for at least this amount of time.) + public long FGSERVICE_MIN_SHOWN_TIME = DEFAULT_FGSERVICE_MIN_SHOWN_TIME; + + // If a foreground service is shown for less than FGSERVICE_MIN_SHOWN_TIME, we will display + // the background app running notification about it for at least this amount of time (if it + // is larger than the remaining shown time). + public long FGSERVICE_MIN_REPORT_TIME = DEFAULT_FGSERVICE_MIN_REPORT_TIME; + + // The minimum amount of time the foreground service needs to have remain being shown + // before the screen goes on for us to consider it not worth showing to the user. That is + // if an app has a foreground service that stops itself this amount of time or more before + // the user turns on the screen, we will just let it go without the user being told about it. + public long FGSERVICE_SCREEN_ON_BEFORE_TIME = DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME; + + // The minimum amount of time a foreground service should remain reported to the user if + // it is stopped when the screen turns on. This is the time from when the screen turns + // on until we will stop reporting it. + public long FGSERVICE_SCREEN_ON_AFTER_TIME = DEFAULT_FGSERVICE_SCREEN_ON_AFTER_TIME; // How long we will retain processes hosting content providers in the "last activity" // state before allowing them to drop down to the regular cached LRU list. This is @@ -225,8 +252,14 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_MAX_CACHED_PROCESSES); BACKGROUND_SETTLE_TIME = mParser.getLong(KEY_BACKGROUND_SETTLE_TIME, DEFAULT_BACKGROUND_SETTLE_TIME); - FOREGROUND_SERVICE_UI_MIN_TIME = mParser.getLong(KEY_FOREGROUND_SERVICE_UI_MIN_TIME, - DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME); + FGSERVICE_MIN_SHOWN_TIME = mParser.getLong(KEY_FGSERVICE_MIN_SHOWN_TIME, + DEFAULT_FGSERVICE_MIN_SHOWN_TIME); + FGSERVICE_MIN_REPORT_TIME = mParser.getLong(KEY_FGSERVICE_MIN_REPORT_TIME, + DEFAULT_FGSERVICE_MIN_REPORT_TIME); + FGSERVICE_SCREEN_ON_BEFORE_TIME = mParser.getLong(KEY_FGSERVICE_SCREEN_ON_BEFORE_TIME, + DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME); + FGSERVICE_SCREEN_ON_AFTER_TIME = mParser.getLong(KEY_FGSERVICE_SCREEN_ON_AFTER_TIME, + DEFAULT_FGSERVICE_SCREEN_ON_AFTER_TIME); CONTENT_PROVIDER_RETAIN_TIME = mParser.getLong(KEY_CONTENT_PROVIDER_RETAIN_TIME, DEFAULT_CONTENT_PROVIDER_RETAIN_TIME); GC_TIMEOUT = mParser.getLong(KEY_GC_TIMEOUT, @@ -284,8 +317,14 @@ final class ActivityManagerConstants extends ContentObserver { pw.println(MAX_CACHED_PROCESSES); pw.print(" "); pw.print(KEY_BACKGROUND_SETTLE_TIME); pw.print("="); pw.println(BACKGROUND_SETTLE_TIME); - pw.print(" "); pw.print(KEY_FOREGROUND_SERVICE_UI_MIN_TIME); pw.print("="); - pw.println(FOREGROUND_SERVICE_UI_MIN_TIME); + pw.print(" "); pw.print(KEY_FGSERVICE_MIN_SHOWN_TIME); pw.print("="); + pw.println(FGSERVICE_MIN_SHOWN_TIME); + pw.print(" "); pw.print(KEY_FGSERVICE_MIN_REPORT_TIME); pw.print("="); + pw.println(FGSERVICE_MIN_REPORT_TIME); + pw.print(" "); pw.print(KEY_FGSERVICE_SCREEN_ON_BEFORE_TIME); pw.print("="); + pw.println(FGSERVICE_SCREEN_ON_BEFORE_TIME); + pw.print(" "); pw.print(KEY_FGSERVICE_SCREEN_ON_AFTER_TIME); pw.print("="); + pw.println(FGSERVICE_SCREEN_ON_AFTER_TIME); pw.print(" "); pw.print(KEY_CONTENT_PROVIDER_RETAIN_TIME); pw.print("="); pw.println(CONTENT_PROVIDER_RETAIN_TIME); pw.print(" "); pw.print(KEY_GC_TIMEOUT); pw.print("="); diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java index ff5efde27f93..f440100b7621 100644 --- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java +++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java @@ -79,6 +79,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_SAVED_STATE = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_SCREENSHOTS = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_SERVICE = DEBUG_ALL || false; + static final boolean DEBUG_FOREGROUND_SERVICE = DEBUG_ALL || false; static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false; static final boolean DEBUG_STACK = DEBUG_ALL || false; static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false; |