Merge "Work on issue #36891897: Need to ensure foreground services..." into oc-dev

This commit is contained in:
Dianne Hackborn
2017-06-15 18:45:28 +00:00
committed by Android (Google) Code Review
7 changed files with 216 additions and 49 deletions

View File

@@ -695,6 +695,14 @@ public class Handler {
return mQueue.hasMessages(this, what, null);
}
/**
* 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() + ") {"

View File

@@ -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 */

View File

@@ -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()

View File

@@ -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)

View File

@@ -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), " ");
}
}
}

View File

@@ -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("=");

View File

@@ -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;