From f0f94d129b6eb3c48624e915898d86d4f2de59ff Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 17 Mar 2014 16:04:21 -0700 Subject: [PATCH] Treat IME processes as hosting activities When we stop using an IME process, we still treat that process as if it is hosting activities (in the activity part of the LRU list), to try to keep it around. This is intended to help the experience of switching between IMEs, reducing the chance of your previous IME process being killed and thus requiring much more time to switch. Change-Id: Ie5793fd9b40d980fa18f80246326511ed6ae0597 --- core/java/android/content/Context.java | 10 +++++++ .../server/InputMethodManagerService.java | 6 +++-- .../com/android/server/am/ActiveServices.java | 20 +++++++++++--- .../server/am/ActivityManagerService.java | 26 ++++++++++++++----- .../com/android/server/am/ProcessRecord.java | 6 +++-- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 81a886ab40ca2..134ffa94cf047 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -241,6 +241,16 @@ public abstract class Context { */ public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080; + /** + * @hide Flag for {@link #bindService}: Treat the binding as hosting + * an activity, an unbinding as the activity going in the background. + * That is, when unbinding, the process when empty will go on the activity + * LRU list instead of the regular one, keeping it around more aggressively + * than it otherwise would be. This is intended for use with IMEs to try + * to keep IME processes around for faster keyboard switching. + */ + public static final int BIND_TREAT_LIKE_ACTIVITY = 0x08000000; + /** * @hide An idea that is not yet implemented. * Flag for {@link #bindService}: If binding from an activity, consider diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 6827b3f508626..af8a6e7504e7f 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -1225,7 +1225,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0)); if (bindCurrentInputMethodService(mCurIntent, this, Context.BIND_AUTO_CREATE - | Context.BIND_NOT_VISIBLE | Context.BIND_SHOWING_UI)) { + | Context.BIND_NOT_VISIBLE | Context.BIND_NOT_FOREGROUND + | Context.BIND_SHOWING_UI)) { mLastBindTime = SystemClock.uptimeMillis(); mHaveConnection = true; mCurId = info.getId(); @@ -1783,7 +1784,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mInputShown = true; if (mHaveConnection && !mVisibleBound) { bindCurrentInputMethodService( - mCurIntent, mVisibleConnection, Context.BIND_AUTO_CREATE); + mCurIntent, mVisibleConnection, Context.BIND_AUTO_CREATE + | Context.BIND_TREAT_LIKE_ACTIVITY); mVisibleBound = true; } res = true; diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index a84512723a8b1..1345cfd038796 100755 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -667,8 +667,7 @@ public final class ActiveServices { // what they are, so we can report this elsewhere for // others to know why certain services are running. try { - clientIntent = (PendingIntent)service.getParcelableExtra( - Intent.EXTRA_CLIENT_INTENT); + clientIntent = service.getParcelableExtra(Intent.EXTRA_CLIENT_INTENT); } catch (RuntimeException e) { } if (clientIntent != null) { @@ -682,6 +681,11 @@ public final class ActiveServices { } } + if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { + mAm.enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, + "BIND_TREAT_LIKE_ACTIVITY"); + } + final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE; ServiceLookupResult res = @@ -755,8 +759,12 @@ public final class ActiveServices { } if (s.app != null) { + if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { + s.app.treatLikeActivity = true; + } // This could have made the service more important. - mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client); + mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities + || s.app.treatLikeActivity, b.client); mAm.updateOomAdjLocked(s.app); } @@ -858,6 +866,12 @@ public final class ActiveServices { if (r.binding.service.app != null) { // This could have made the service less important. + if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { + r.binding.service.app.treatLikeActivity = true; + mAm.updateLruProcessLocked(r.binding.service.app, + r.binding.service.app.hasClientActivities + || r.binding.service.app.treatLikeActivity, null); + } mAm.updateOomAdjLocked(r.binding.service.app); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ab7d60aa41184..c7af55cb23ff0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2314,11 +2314,12 @@ public final class ActivityManagerService extends ActivityManagerNative final void updateLruProcessLocked(ProcessRecord app, boolean activityChange, ProcessRecord client) { - final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities; + final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities + || app.treatLikeActivity; final boolean hasService = false; // not impl yet. app.services.size() > 0; if (!activityChange && hasActivity) { - // The process has activties, so we are only going to allow activity-based - // adjustments move it. It should be kept in the front of the list with other + // The process has activities, so we are only allowing activity-based adjustments + // to move it. It should be kept in the front of the list with other // processes that have activities, and we don't want those to change their // order except due to activity operations. return; @@ -12561,6 +12562,7 @@ public final class ActivityManagerService extends ActivityManagerNative updateProcessForegroundLocked(app, false, false); app.foregroundActivities = false; app.hasShownUi = false; + app.treatLikeActivity = false; app.hasAboveClient = false; mServices.killServicesLocked(app, allowRestart); @@ -14852,6 +14854,9 @@ public final class ActivityManagerService extends ActivityManagerNative app.adjTarget = s.name; } } + if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) { + app.treatLikeActivity = true; + } final ActivityRecord a = cr.activity; if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) { if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ && @@ -14984,10 +14989,17 @@ public final class ActivityManagerService extends ActivityManagerNative } } - if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY && app.hasClientActivities) { - // This is a cached process, but with client activities. Mark it so. - procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT; - app.adjType = "cch-client-act"; + if (procState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) { + if (app.hasClientActivities) { + // This is a cached process, but with client activities. Mark it so. + procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT; + app.adjType = "cch-client-act"; + } else if (app.treatLikeActivity) { + // This is a cached process, but somebody wants us to treat it like it has + // an activity, okay! + procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; + app.adjType = "cch-as-act"; + } } if (adj == ProcessList.SERVICE_ADJ) { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 10574ed392e68..d04a6b211a61f 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -95,6 +95,7 @@ final class ProcessRecord { boolean hasShownUi; // Has UI been shown in this process since it was started? boolean pendingUiClean; // Want to clean up resources from showing UI? boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower + boolean treatLikeActivity; // Bound using BIND_TREAT_LIKE_ACTIVITY boolean bad; // True if disabled in the bad process list boolean killedByAm; // True when proc has been killed by activity manager, not for RAM boolean procStateChanged; // Keep track of whether we changed 'setAdj'. @@ -251,10 +252,11 @@ final class ProcessRecord { pw.print(" lastStateTime="); TimeUtils.formatDuration(lastStateTime, now, pw); pw.println(); - if (hasShownUi || pendingUiClean || hasAboveClient) { + if (hasShownUi || pendingUiClean || hasAboveClient || treatLikeActivity) { pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi); pw.print(" pendingUiClean="); pw.print(pendingUiClean); - pw.print(" hasAboveClient="); pw.println(hasAboveClient); + 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);