summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt42
-rw-r--r--core/java/android/app/Activity.java22
-rw-r--r--core/java/android/app/ActivityThread.java32
-rw-r--r--core/java/android/app/Application.java160
-rw-r--r--core/java/android/app/ContextImpl.java6
-rw-r--r--core/java/android/app/Fragment.java8
-rw-r--r--core/java/android/app/FragmentManager.java11
-rw-r--r--core/java/android/app/Service.java9
-rw-r--r--core/java/android/content/ComponentCallbacks.java9
-rw-r--r--core/java/android/content/ComponentCallbacks2.java66
-rw-r--r--core/java/android/content/ContentProvider.java5
-rw-r--r--core/java/android/content/Context.java82
-rw-r--r--core/java/android/view/HardwareRenderer.java6
-rw-r--r--core/java/android/view/ViewRootImpl.java3
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java222
-rw-r--r--services/java/com/android/server/am/ActivityStack.java1
-rw-r--r--services/java/com/android/server/am/AppBindRecord.java2
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java21
18 files changed, 596 insertions, 111 deletions
diff --git a/api/current.txt b/api/current.txt
index 91cf3fa..fed520c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2331,7 +2331,7 @@ package android.app {
method public abstract void onTabUnselected(android.app.ActionBar.Tab, android.app.FragmentTransaction);
}
- public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
+ public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
ctor public Activity();
method public void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public void closeContextMenu();
@@ -2436,6 +2436,7 @@ package android.app {
method protected void onTitleChanged(java.lang.CharSequence, int);
method public boolean onTouchEvent(android.view.MotionEvent);
method public boolean onTrackballEvent(android.view.MotionEvent);
+ method public void onTrimMemory(int);
method public void onUserInteraction();
method protected void onUserLeaveHint();
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
@@ -2731,12 +2732,25 @@ package android.app {
ctor public AliasActivity();
}
- public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks {
+ public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Application();
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onCreate();
method public void onLowMemory();
method public void onTerminate();
+ method public void onTrimMemory(int);
+ method public void registerActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
+ method public void unregisterActivityLifecycleCallbacks(android.app.Application.ActivityLifecycleCallbacks);
+ }
+
+ public static abstract interface Application.ActivityLifecycleCallbacks {
+ method public abstract void onActivityCreated(android.app.Activity, android.os.Bundle);
+ method public abstract void onActivityDestroyed(android.app.Activity);
+ method public abstract void onActivityPaused(android.app.Activity);
+ method public abstract void onActivityResumed(android.app.Activity);
+ method public abstract void onActivitySaveInstanceState(android.app.Activity, android.os.Bundle);
+ method public abstract void onActivityStarted(android.app.Activity);
+ method public abstract void onActivityStopped(android.app.Activity);
}
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
@@ -2955,7 +2969,7 @@ package android.app {
method public void setSelectedGroup(int);
}
- public class Fragment implements android.content.ComponentCallbacks android.view.View.OnCreateContextMenuListener {
+ public class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
ctor public Fragment();
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public final boolean equals(java.lang.Object);
@@ -3009,6 +3023,7 @@ package android.app {
method public void onSaveInstanceState(android.os.Bundle);
method public void onStart();
method public void onStop();
+ method public void onTrimMemory(int);
method public void onViewCreated(android.view.View, android.os.Bundle);
method public void registerForContextMenu(android.view.View);
method public void setArguments(android.os.Bundle);
@@ -3545,7 +3560,7 @@ package android.app {
field public static final android.os.Parcelable.Creator CREATOR;
}
- public abstract class Service extends android.content.ContextWrapper implements android.content.ComponentCallbacks {
+ public abstract class Service extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Service();
method protected void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public final android.app.Application getApplication();
@@ -3558,6 +3573,7 @@ package android.app {
method public deprecated void onStart(android.content.Intent, int);
method public int onStartCommand(android.content.Intent, int, int);
method public void onTaskRemoved(android.content.Intent);
+ method public void onTrimMemory(int);
method public boolean onUnbind(android.content.Intent);
method public final void startForeground(int, android.app.Notification);
method public final void stopForeground(boolean);
@@ -4442,6 +4458,14 @@ package android.content {
method public abstract void onLowMemory();
}
+ public abstract interface ComponentCallbacks2 implements android.content.ComponentCallbacks {
+ method public abstract void onTrimMemory(int);
+ field public static final int TRIM_MEMORY_BACKGROUND = 40; // 0x28
+ field public static final int TRIM_MEMORY_COMPLETE = 80; // 0x50
+ field public static final int TRIM_MEMORY_MODERATE = 60; // 0x3c
+ field public static final int TRIM_MEMORY_UI_HIDDEN = 20; // 0x14
+ }
+
public final class ComponentName implements java.lang.Cloneable java.lang.Comparable android.os.Parcelable {
ctor public ComponentName(java.lang.String, java.lang.String);
ctor public ComponentName(android.content.Context, java.lang.String);
@@ -4463,7 +4487,7 @@ package android.content {
field public static final android.os.Parcelable.Creator CREATOR;
}
- public abstract class ContentProvider implements android.content.ComponentCallbacks {
+ public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
ctor public ContentProvider();
method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
method public void attachInfo(android.content.Context, android.content.pm.ProviderInfo);
@@ -4481,6 +4505,7 @@ package android.content {
method public void onConfigurationChanged(android.content.res.Configuration);
method public abstract boolean onCreate();
method public void onLowMemory();
+ method public void onTrimMemory(int);
method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
method protected final android.os.ParcelFileDescriptor openFileHelper(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
@@ -4734,6 +4759,7 @@ package android.content {
method public abstract android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
method public abstract android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
method public abstract deprecated android.graphics.drawable.Drawable peekWallpaper();
+ method public void registerComponentCallbacks(android.content.ComponentCallbacks);
method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
method public abstract void removeStickyBroadcast(android.content.Intent);
@@ -4754,15 +4780,21 @@ package android.content {
method public abstract android.content.ComponentName startService(android.content.Intent);
method public abstract boolean stopService(android.content.Intent);
method public abstract void unbindService(android.content.ServiceConnection);
+ method public void unregisterComponentCallbacks(android.content.ComponentCallbacks);
method public abstract void unregisterReceiver(android.content.BroadcastReceiver);
field public static final java.lang.String ACCESSIBILITY_SERVICE = "accessibility";
field public static final java.lang.String ACCOUNT_SERVICE = "account";
field public static final java.lang.String ACTIVITY_SERVICE = "activity";
field public static final java.lang.String ALARM_SERVICE = "alarm";
field public static final java.lang.String AUDIO_SERVICE = "audio";
+ field public static final int BIND_ABOVE_CLIENT = 8; // 0x8
+ field public static final int BIND_ADJUST_WITH_ACTIVITY = 64; // 0x40
+ field public static final int BIND_ALLOW_OOM_MANAGEMENT = 16; // 0x10
field public static final int BIND_AUTO_CREATE = 1; // 0x1
field public static final int BIND_DEBUG_UNBIND = 2; // 0x2
+ field public static final int BIND_IMPORTANT = 64; // 0x40
field public static final int BIND_NOT_FOREGROUND = 4; // 0x4
+ field public static final int BIND_WAIVE_PRIORITY = 32; // 0x20
field public static final java.lang.String CLIPBOARD_SERVICE = "clipboard";
field public static final java.lang.String CONNECTIVITY_SERVICE = "connectivity";
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index fb1570e..d5b669e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -19,7 +19,7 @@ package android.app;
import com.android.internal.app.ActionBarImpl;
import com.android.internal.policy.PolicyManager;
-import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -626,7 +626,7 @@ import java.util.HashMap;
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
- OnCreateContextMenuListener, ComponentCallbacks {
+ OnCreateContextMenuListener, ComponentCallbacks2 {
private static final String TAG = "Activity";
/** Standard activity result: operation canceled. */
@@ -859,6 +859,7 @@ public class Activity extends ContextThemeWrapper
? mLastNonConfigurationInstances.fragments : null);
}
mFragments.dispatchCreate();
+ getApplication().dispatchActivityCreated(this, savedInstanceState);
mCalled = true;
}
@@ -1001,6 +1002,8 @@ public class Activity extends ContextThemeWrapper
}
mCheckedForLoaderManager = true;
}
+
+ getApplication().dispatchActivityStarted(this);
}
/**
@@ -1048,6 +1051,7 @@ public class Activity extends ContextThemeWrapper
* @see #onPause
*/
protected void onResume() {
+ getApplication().dispatchActivityResumed(this);
mCalled = true;
}
@@ -1158,6 +1162,7 @@ public class Activity extends ContextThemeWrapper
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
+ getApplication().dispatchActivitySaveInstanceState(this, outState);
}
/**
@@ -1234,6 +1239,7 @@ public class Activity extends ContextThemeWrapper
* @see #onStop
*/
protected void onPause() {
+ getApplication().dispatchActivityPaused(this);
mCalled = true;
}
@@ -1320,6 +1326,7 @@ public class Activity extends ContextThemeWrapper
*/
protected void onStop() {
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
+ getApplication().dispatchActivityStopped(this);
mCalled = true;
}
@@ -1382,6 +1389,8 @@ public class Activity extends ContextThemeWrapper
if (mSearchManager != null) {
mSearchManager.stopSearch();
}
+
+ getApplication().dispatchActivityDestroyed(this);
}
/**
@@ -1580,12 +1589,17 @@ public class Activity extends ContextThemeWrapper
nci.loaders = mAllLoaderManagers;
return nci;
}
-
+
public void onLowMemory() {
mCalled = true;
mFragments.dispatchLowMemory();
}
-
+
+ public void onTrimMemory(int level) {
+ mCalled = true;
+ mFragments.dispatchTrimMemory(level);
+ }
+
/**
* Return the FragmentManager for interacting with fragments associated
* with this activity.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1e93f88..8931675 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -18,7 +18,7 @@ package android.app;
import android.app.backup.BackupAgent;
import android.content.BroadcastReceiver;
-import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.Context;
@@ -3258,10 +3258,10 @@ public final class ActivityThread {
}
}
- ArrayList<ComponentCallbacks> collectComponentCallbacksLocked(
+ ArrayList<ComponentCallbacks2> collectComponentCallbacksLocked(
boolean allActivities, Configuration newConfig) {
- ArrayList<ComponentCallbacks> callbacks
- = new ArrayList<ComponentCallbacks>();
+ ArrayList<ComponentCallbacks2> callbacks
+ = new ArrayList<ComponentCallbacks2>();
if (mActivities.size() > 0) {
Iterator<ActivityClientRecord> it = mActivities.values().iterator();
@@ -3311,10 +3311,10 @@ public final class ActivityThread {
return callbacks;
}
- private void performConfigurationChanged(
- ComponentCallbacks cb, Configuration config) {
+ private final void performConfigurationChanged(
+ ComponentCallbacks2 cb, Configuration config) {
// Only for Activity objects, check that they actually call up to their
- // superclass implementation. ComponentCallbacks is an interface, so
+ // superclass implementation. ComponentCallbacks2 is an interface, so
// we check the runtime type and act accordingly.
Activity activity = (cb instanceof Activity) ? (Activity) cb : null;
if (activity != null) {
@@ -3418,7 +3418,7 @@ public final class ActivityThread {
final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
- ArrayList<ComponentCallbacks> callbacks = null;
+ ArrayList<ComponentCallbacks2> callbacks = null;
synchronized (mPackages) {
if (mPendingConfiguration != null) {
@@ -3558,7 +3558,7 @@ public final class ActivityThread {
}
final void handleLowMemory() {
- ArrayList<ComponentCallbacks> callbacks;
+ ArrayList<ComponentCallbacks2> callbacks;
synchronized (mPackages) {
callbacks = collectComponentCallbacksLocked(true, null);
@@ -3583,6 +3583,16 @@ public final class ActivityThread {
final void handleTrimMemory(int level) {
WindowManagerImpl.getDefault().trimMemory(level);
+ ArrayList<ComponentCallbacks2> callbacks;
+
+ synchronized (mPackages) {
+ callbacks = collectComponentCallbacksLocked(true, null);
+ }
+
+ final int N = callbacks.size();
+ for (int i=0; i<N; i++) {
+ callbacks.get(i).onTrimMemory(level);
+ }
}
private void handleBindApplication(AppBindData data) {
@@ -4128,7 +4138,7 @@ public final class ActivityThread {
}
}
- ViewRootImpl.addConfigCallback(new ComponentCallbacks() {
+ ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
public void onConfigurationChanged(Configuration newConfig) {
synchronized (mPackages) {
// We need to apply this change to the resources
@@ -4148,6 +4158,8 @@ public final class ActivityThread {
}
public void onLowMemory() {
}
+ public void onTrimMemory(int level) {
+ }
});
}
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 10cc9f8..dd9ea26 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -16,10 +16,14 @@
package android.app;
+import java.util.ArrayList;
+
import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
+import android.os.Bundle;
/**
* Base class for those who need to maintain global application state. You can
@@ -36,10 +40,25 @@ import android.content.res.Configuration;
* {@link android.content.Context#getApplicationContext() Context.getApplicationContext()}
* when first constructing the singleton.</p>
*/
-public class Application extends ContextWrapper implements ComponentCallbacks {
+public class Application extends ContextWrapper implements ComponentCallbacks2 {
+ private ArrayList<ComponentCallbacks> mComponentCallbacks =
+ new ArrayList<ComponentCallbacks>();
+ private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
+ new ArrayList<ActivityLifecycleCallbacks>();
+
/** @hide */
public LoadedApk mLoadedApk;
-
+
+ public interface ActivityLifecycleCallbacks {
+ void onActivityCreated(Activity activity, Bundle savedInstanceState);
+ void onActivityStarted(Activity activity);
+ void onActivityResumed(Activity activity);
+ void onActivityPaused(Activity activity);
+ void onActivityStopped(Activity activity);
+ void onActivitySaveInstanceState(Activity activity, Bundle outState);
+ void onActivityDestroyed(Activity activity);
+ }
+
public Application() {
super(null);
}
@@ -63,11 +82,59 @@ public class Application extends ContextWrapper implements ComponentCallbacks {
*/
public void onTerminate() {
}
-
+
public void onConfigurationChanged(Configuration newConfig) {
+ Object[] callbacks = collectComponentCallbacks();
+ if (callbacks != null) {
+ for (int i=0; i<callbacks.length; i++) {
+ ((ComponentCallbacks)callbacks[i]).onConfigurationChanged(newConfig);
+ }
+ }
}
-
+
public void onLowMemory() {
+ Object[] callbacks = collectComponentCallbacks();
+ if (callbacks != null) {
+ for (int i=0; i<callbacks.length; i++) {
+ ((ComponentCallbacks)callbacks[i]).onLowMemory();
+ }
+ }
+ }
+
+ public void onTrimMemory(int level) {
+ Object[] callbacks = collectComponentCallbacks();
+ if (callbacks != null) {
+ for (int i=0; i<callbacks.length; i++) {
+ Object c = callbacks[i];
+ if (c instanceof ComponentCallbacks2) {
+ ((ComponentCallbacks2)c).onTrimMemory(level);
+ }
+ }
+ }
+ }
+
+ public void registerComponentCallbacks(ComponentCallbacks callback) {
+ synchronized (mComponentCallbacks) {
+ mComponentCallbacks.add(callback);
+ }
+ }
+
+ public void unregisterComponentCallbacks(ComponentCallbacks callback) {
+ synchronized (mComponentCallbacks) {
+ mComponentCallbacks.remove(callback);
+ }
+ }
+
+ public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
+ synchronized (mActivityLifecycleCallbacks) {
+ mActivityLifecycleCallbacks.add(callback);
+ }
+ }
+
+ public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
+ synchronized (mActivityLifecycleCallbacks) {
+ mActivityLifecycleCallbacks.remove(callback);
+ }
}
// ------------------ Internal API ------------------
@@ -79,4 +146,89 @@ public class Application extends ContextWrapper implements ComponentCallbacks {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
+
+ /* package */ void dispatchActivityCreated(Activity activity, Bundle savedInstanceState) {
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i=0; i<callbacks.length; i++) {
+ ((ActivityLifecycleCallbacks)callbacks[i]).onActivityCreated(activity,
+ savedInstanceState);
+ }
+ }
+ }
+
+ /* package */ void dispatchActivityStarted(Activity activity) {
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i=0; i<callbacks.length; i++) {
+ ((ActivityLifecycleCallbacks)callbacks[i]).onActivityStarted(activity);
+ }
+ }
+ }
+
+ /* package */ void dispatchActivityResumed(Activity activity) {
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i=0; i<callbacks.length; i++) {
+ ((ActivityLifecycleCallbacks)callbacks[i]).onActivityResumed(activity);
+ }
+ }
+ }
+
+ /* package */ void dispatchActivityPaused(Activity activity) {
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i=0; i<callbacks.length; i++) {
+ ((ActivityLifecycleCallbacks)callbacks[i]).onActivityPaused(activity);
+ }
+ }
+ }
+
+ /* package */ void dispatchActivityStopped(Activity activity) {
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i=0; i<callbacks.length; i++) {
+ ((ActivityLifecycleCallbacks)callbacks[i]).onActivityStopped(activity);
+ }
+ }
+ }
+
+ /* package */ void dispatchActivitySaveInstanceState(Activity activity, Bundle outState) {
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i=0; i<callbacks.length; i++) {
+ ((ActivityLifecycleCallbacks)callbacks[i]).onActivitySaveInstanceState(activity,
+ outState);
+ }
+ }
+ }
+
+ /* package */ void dispatchActivityDestroyed(Activity activity) {
+ Object[] callbacks = collectActivityLifecycleCallbacks();
+ if (callbacks != null) {
+ for (int i=0; i<callbacks.length; i++) {
+ ((ActivityLifecycleCallbacks)callbacks[i]).onActivityDestroyed(activity);
+ }
+ }
+ }
+
+ private Object[] collectComponentCallbacks() {
+ Object[] callbacks = null;
+ synchronized (mComponentCallbacks) {
+ if (mComponentCallbacks.size() > 0) {
+ callbacks = mComponentCallbacks.toArray();
+ }
+ }
+ return callbacks;
+ }
+
+ private Object[] collectActivityLifecycleCallbacks() {
+ Object[] callbacks = null;
+ synchronized (mActivityLifecycleCallbacks) {
+ if (mActivityLifecycleCallbacks.size() > 0) {
+ callbacks = mActivityLifecycleCallbacks.toArray();
+ }
+ }
+ return callbacks;
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a99cec2..b4bdb2f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1109,6 +1109,12 @@ class ContextImpl extends Context {
throw new RuntimeException("Not supported in system context");
}
try {
+ IBinder token = getActivityToken();
+ if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
+ && mPackageInfo.getApplicationInfo().targetSdkVersion
+ < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ flags |= BIND_WAIVE_PRIORITY;
+ }
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index e2746d4..371e7ad 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -17,7 +17,7 @@
package android.app;
import android.animation.Animator;
-import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -332,7 +332,7 @@ final class FragmentState implements Parcelable {
* pressing back will pop it to return the user to whatever previous state
* the activity UI was in.
*/
-public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener {
+public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener {
private static final HashMap<String, Class<?>> sClassMap =
new HashMap<String, Class<?>>();
@@ -1182,6 +1182,10 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
mCalled = true;
}
+ public void onTrimMemory(int level) {
+ mCalled = true;
+ }
+
/**
* Called when the view previously created by {@link #onCreateView} has
* been detached from the fragment. The next time the fragment needs
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 24550c5..c33ab2c 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1722,6 +1722,17 @@ final class FragmentManagerImpl extends FragmentManager {
}
}
+ public void dispatchTrimMemory(int level) {
+ if (mActive != null) {
+ for (int i=0; i<mAdded.size(); i++) {
+ Fragment f = mAdded.get(i);
+ if (f != null) {
+ f.onTrimMemory(level);
+ }
+ }
+ }
+ }
+
public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
boolean show = false;
ArrayList<Fragment> newMenus = null;
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 4c21d04..ebde6e0 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -16,7 +16,7 @@
package android.app;
-import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ContextWrapper;
@@ -274,7 +274,7 @@ import java.io.PrintWriter;
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.java
* bind}
*/
-public abstract class Service extends ContextWrapper implements ComponentCallbacks {
+public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
private static final String TAG = "Service";
public Service() {
@@ -451,7 +451,10 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
public void onLowMemory() {
}
-
+
+ public void onTrimMemory(int level) {
+ }
+
/**
* Return the communication channel to the service. May return null if
* clients can not bind to the service. The returned
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index 37cc141..dad60b0 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -51,13 +51,4 @@ public interface ComponentCallbacks {
* The system will perform a gc for you after returning from this method.
*/
void onLowMemory();
-
- /** @hide */
- static final int TRIM_MEMORY_COMPLETE = 80;
-
- /** @hide */
- static final int TRIM_MEMORY_MODERATE = 50;
-
- /** @hide */
- static final int TRIM_MEMORY_BACKGROUND = 20;
}
diff --git a/core/java/android/content/ComponentCallbacks2.java b/core/java/android/content/ComponentCallbacks2.java
new file mode 100644
index 0000000..8b9f97c
--- /dev/null
+++ b/core/java/android/content/ComponentCallbacks2.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2006 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 android.content;
+
+/**
+ * Extended {@link ComponentCallbacks} interface with a new callback for
+ * finer-grained memory management.
+ */
+public interface ComponentCallbacks2 extends ComponentCallbacks {
+
+ /**
+ * Level for {@link #onTrimMemory(int)}: the process is nearing the end
+ * of the background LRU list, and if more memory isn't found soon it will
+ * be killed.
+ */
+ static final int TRIM_MEMORY_COMPLETE = 80;
+
+ /**
+ * Level for {@link #onTrimMemory(int)}: the process is around the middle
+ * of the background LRU list; freeing memory can help the system keep
+ * other processes running later in the list for better overall performance.
+ */
+ static final int TRIM_MEMORY_MODERATE = 60;
+
+ /**
+ * Level for {@link #onTrimMemory(int)}: the process has gone on to the
+ * LRU list. This is a good opportunity to clean up resources that can
+ * efficiently and quickly be re-built if the user returns to the app.
+ */
+ static final int TRIM_MEMORY_BACKGROUND = 40;
+
+ /**
+ * Level for {@link #onTrimMemory(int)}: the process had been showing
+ * a user interface, and is no longer doing so. Large allocations with
+ * the UI should be released at this point to allow memory to be better
+ * managed.
+ */
+ static final int TRIM_MEMORY_UI_HIDDEN = 20;
+
+ /**
+ * Called when the operating system has determined that it is a good
+ * time for a process to trim unneeded memory from its process. This will
+ * happen for example when it goes in the background and there is not enough
+ * memory to keep as many background processes running as desired.
+ *
+ * @param level The context of the trim, giving a hint of the amount of
+ * trimming the application may like to perform. May be
+ * {@link #TRIM_MEMORY_COMPLETE}, {@link #TRIM_MEMORY_MODERATE},
+ * {@link #TRIM_MEMORY_BACKGROUND}, or {@link #TRIM_MEMORY_UI_HIDDEN}.
+ */
+ void onTrimMemory(int level);
+}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 1a5c675..8057d4b 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -78,7 +78,7 @@ import java.util.ArrayList;
* ContentProvider instance, so subclasses don't have to worry about the details of
* cross-process calls.</p>
*/
-public abstract class ContentProvider implements ComponentCallbacks {
+public abstract class ContentProvider implements ComponentCallbacks2 {
private static final String TAG = "ContentProvider";
/*
@@ -491,6 +491,9 @@ public abstract class ContentProvider implements ComponentCallbacks {
public void onLowMemory() {
}
+ public void onTrimMemory(int level) {
+ }
+
/**
* Implement this to handle query requests from clients.
* This method can be called from multiple threads, as described in
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2a02446..46712a9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -107,12 +107,17 @@ public abstract class Context {
* this still provides you with access to the service object while the
* service is created.
*
- * <p>Specifying this flag also tells the system to treat the service
- * as being as important as your own process -- that is, when deciding
- * which process should be killed to free memory, the service will only
- * be considered a candidate as long as the processes of any such bindings
- * is also a candidate to be killed. This is to avoid situations where
- * the service is being continually created and killed due to low memory.
+ * <p>Note that prior to {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH},
+ * not supplying this flag would also impact how important the system
+ * consider's the target service's process to be. When set, the only way
+ * for it to be raised was by binding from a service in which case it will
+ * only be important when that activity is in the foreground. Now to
+ * achieve this behavior you must explicitly supply the new flag
+ * {@link #BIND_ADJUST_WITH_ACTIVITY}. For compatibility, old applications
+ * that don't specify {@link #BIND_AUTO_CREATE} will automatically have
+ * the flags {@link #BIND_WAIVE_PRIORITY} and
+ * {@link #BIND_ADJUST_WITH_ACTIVITY} set for them in order to achieve
+ * the same result.
*/
public static final int BIND_AUTO_CREATE = 0x0001;
@@ -139,14 +144,48 @@ public abstract class Context {
public static final int BIND_NOT_FOREGROUND = 0x0004;
/**
+ * Flag for {@link #bindService}: indicates that the client application
+ * binding to this service considers the service to be more important than
+ * the app itself. When set, the platform will try to have the out of
+ * memory kill the app before it kills the service it is bound to, though
+ * this is not guaranteed to be the case.
+ */
+ public static final int BIND_ABOVE_CLIENT = 0x0008;
+
+ /**
* Flag for {@link #bindService}: allow the process hosting the bound
* service to go through its normal memory management. It will be
* treated more like a running service, allowing the system to
* (temporarily) expunge the process if low on memory or for some other
- * whim it may have.
- * @hide
+ * whim it may have, and being more aggressive about making it a candidate
+ * to be killed (and restarted) if running for a long time.
*/
- public static final int BIND_ALLOW_OOM_MANAGEMENT = 0x0008;
+ public static final int BIND_ALLOW_OOM_MANAGEMENT = 0x0010;
+
+ /**
+ * Flag for {@link #bindService}: don't impact the scheduling or
+ * memory management priority of the target service's hosting process.
+ * Allows the service's process to be managed on the background LRU list
+ * just like a regular application process in the background.
+ */
+ public static final int BIND_WAIVE_PRIORITY = 0x0020;
+
+ /**
+ * Flag for {@link #bindService}: this service is very important to
+ * the client, so should be brought to the foreground process level
+ * when the client is. Normally a process can only be raised to the
+ * visibility level by a client, even if that client is in the foreground.
+ */
+ public static final int BIND_IMPORTANT = 0x0040;
+
+ /**
+ * Flag for {@link #bindService}: If binding from an activity, allow the
+ * target service's process importance to be raised based on whether the
+ * activity is visible to the user, regardless whether another flag is
+ * used to reduce the amount that the client process's overall importance
+ * is used to impact it.
+ */
+ public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0040;
/** Return an AssetManager instance for your application's package. */
public abstract AssetManager getAssets();
@@ -195,6 +234,25 @@ public abstract class Context {
public abstract Context getApplicationContext();
/**
+ * Add a new {@link ComponentCallbacks} to the base application of the
+ * Context, which will be called at the same times as the ComponentCallbacks
+ * methods of activities and other components are called. Note that you
+ * <em>must</em> be sure to use {@link #unregisterComponentCallbacks} when
+ * appropriate in the future; this will not be removed for you.
+ */
+ public void registerComponentCallbacks(ComponentCallbacks callback) {
+ getApplicationContext().registerComponentCallbacks(callback);
+ }
+
+ /**
+ * Remove a {@link ComponentCallbacks} objec that was previously registered
+ * with {@link #registerComponentCallbacks(ComponentCallbacks)}.
+ */
+ public void unregisterComponentCallbacks(ComponentCallbacks callback) {
+ getApplicationContext().unregisterComponentCallbacks(callback);
+ }
+
+ /**
* Return a localized, styled CharSequence from the application's package's
* default string table.
*
@@ -1219,8 +1277,10 @@ public abstract class Context {
* {@link IntentFilter} published by a service.
* @param conn Receives information as the service is started and stopped.
* @param flags Operation options for the binding. May be 0,
- * {@link #BIND_AUTO_CREATE}, {@link #BIND_DEBUG_UNBIND}, or
- * {@link #BIND_NOT_FOREGROUND}.
+ * {@link #BIND_AUTO_CREATE}, {@link #BIND_DEBUG_UNBIND},
+ * {@link #BIND_NOT_FOREGROUND}, {@link #BIND_ABOVE_CLIENT},
+ * {@link #BIND_ALLOW_OOM_MANAGEMENT}, or
+ * {@link #BIND_WAIVE_PRIORITY}.
* @return If you have successfully bound to the service, true is returned;
* false is returned if the connection is not made so you will not
* receive the service object.
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 4e4923b..4e20358 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -17,7 +17,7 @@
package android.view;
-import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
@@ -975,10 +975,10 @@ public abstract class HardwareRenderer {
}
switch (level) {
- case ComponentCallbacks.TRIM_MEMORY_MODERATE:
+ case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
break;
- case ComponentCallbacks.TRIM_MEMORY_COMPLETE:
+ case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
break;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0bd5a2a..b22ab7e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -21,6 +21,7 @@ import android.animation.LayoutTransition;
import android.app.ActivityManagerNative;
import android.content.ClipDescription;
import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
@@ -554,7 +555,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (mThread != Thread.currentThread()) {
if (mAttachInfo.mHardwareRenderer != null &&
mAttachInfo.mHardwareRenderer.isEnabled()) {
- HardwareRenderer.trimMemory(ComponentCallbacks.TRIM_MEMORY_MODERATE);
+ HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
}
} else {
if (mAttachInfo.mHardwareRenderer != null &&
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 66f88fc..14c6306 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -53,7 +53,7 @@ import android.app.Service;
import android.app.backup.IBackupManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
-import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -8067,6 +8067,21 @@ public final class ActivityManagerService extends ActivityManagerNative
if (needSep) pw.println(" ");
needSep = true;
+ pw.println(" OOM levels:");
+ pw.print(" SYSTEM_ADJ: "); pw.println(SYSTEM_ADJ);
+ pw.print(" CORE_SERVER_ADJ: "); pw.println(CORE_SERVER_ADJ);
+ pw.print(" FOREGROUND_APP_ADJ: "); pw.println(FOREGROUND_APP_ADJ);
+ pw.print(" VISIBLE_APP_ADJ: "); pw.println(VISIBLE_APP_ADJ);
+ pw.print(" PERCEPTIBLE_APP_ADJ: "); pw.println(PERCEPTIBLE_APP_ADJ);
+ pw.print(" HEAVY_WEIGHT_APP_ADJ: "); pw.println(HEAVY_WEIGHT_APP_ADJ);
+ pw.print(" BACKUP_APP_ADJ: "); pw.println(BACKUP_APP_ADJ);
+ pw.print(" SECONDARY_SERVER_ADJ: "); pw.println(SECONDARY_SERVER_ADJ);
+ pw.print(" HOME_APP_ADJ: "); pw.println(HOME_APP_ADJ);
+ pw.print(" HIDDEN_APP_MIN_ADJ: "); pw.println(HIDDEN_APP_MIN_ADJ);
+ pw.print(" EMPTY_APP_ADJ: "); pw.println(EMPTY_APP_ADJ);
+
+ if (needSep) pw.println(" ");
+ needSep = true;
pw.println(" Process OOM control:");
dumpProcessOomList(pw, this, procs, " ",
"Proc", "PERS", true);
@@ -8814,7 +8829,8 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.print(" ");
pw.print("keeping="); pw.print(r.keeping);
pw.print(" hidden="); pw.print(r.hidden);
- pw.print(" empty="); pw.println(r.empty);
+ pw.print(" empty="); pw.print(r.empty);
+ pw.print(" hasAboveClient="); pw.println(r.hasAboveClient);
if (!r.keeping) {
if (r.lastWakeTime != 0) {
@@ -9226,6 +9242,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.foregroundServices = false;
app.foregroundActivities = false;
app.hasShownUi = false;
+ app.hasAboveClient = false;
killServicesLocked(app, allowRestart);
@@ -10452,6 +10469,9 @@ public final class ActivityManagerService extends ActivityManagerNative
activity.connections.add(c);
}
b.client.connections.add(c);
+ if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
+ b.client.hasAboveClient = true;
+ }
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
@@ -10523,6 +10543,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (b.client != skipApp) {
b.client.connections.remove(c);
+ if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
+ b.client.updateHasAboveClientLocked();
+ }
}
clist = mServiceConnections.get(binder);
if (clist != null) {
@@ -12577,9 +12600,9 @@ public final class ActivityManagerService extends ActivityManagerNative
// an earlier hidden adjustment that isn't really for us... if
// so, use the new hidden adjustment.
if (!recursed && app.hidden) {
- app.curAdj = hiddenAdj;
+ app.curAdj = app.curRawAdj = hiddenAdj;
}
- return app.curAdj;
+ return app.curRawAdj;
}
if (app.thread == null) {
@@ -12588,28 +12611,47 @@ public final class ActivityManagerService extends ActivityManagerNative
return (app.curAdj=EMPTY_APP_ADJ);
}
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
+ app.adjSource = null;
+ app.adjTarget = null;
+ app.empty = false;
+ app.hidden = false;
+
+ final int activitiesSize = app.activities.size();
+
if (app.maxAdj <= FOREGROUND_APP_ADJ) {
// The max adjustment doesn't allow this app to be anything
// below foreground, so it is not worth doing work for it.
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
+ app.foregroundActivities = false;
app.keeping = true;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
+ // System process can do UI, and when they do we want to have
+ // them trim their memory after the user leaves the UI. To
+ // facilitate this, here we need to determine whether or not it
+ // is currently showing UI.
+ app.systemNoUi = true;
+ if (app == TOP_APP) {
+ app.systemNoUi = false;
+ } else if (activitiesSize > 0) {
+ for (int j = 0; j < activitiesSize; j++) {
+ final ActivityRecord r = app.activities.get(j);
+ if (r.visible) {
+ app.systemNoUi = false;
+ break;
+ }
+ }
+ }
return (app.curAdj=app.maxAdj);
}
final boolean hadForegroundActivities = app.foregroundActivities;
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
- app.adjSource = null;
- app.adjTarget = null;
- app.keeping = false;
- app.empty = false;
- app.hidden = false;
app.foregroundActivities = false;
-
- final int activitiesSize = app.activities.size();
+ app.keeping = false;
+ app.systemNoUi = false;
// Determine the importance of the process, starting with most
// important to least, and assign an appropriate OOM adjustment.
@@ -12784,7 +12826,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Binding to ourself is not interesting.
continue;
}
- if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
+ if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
ProcessRecord client = cr.binding.client;
int clientAdj = adj;
int myHiddenAdj = hiddenAdj;
@@ -12825,15 +12867,32 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
if (adj > clientAdj) {
- adj = clientAdj >= VISIBLE_APP_ADJ
- ? clientAdj : VISIBLE_APP_ADJ;
- if (!client.hidden) {
- app.hidden = false;
- }
- if (client.keeping) {
- app.keeping = true;
+ // If this process has recently shown UI, and
+ // the process that is binding to it is less
+ // important than being visible, then we don't
+ // care about the binding as much as we care
+ // about letting this process get into the LRU
+ // list to be killed and restarted if needed for
+ // memory.
+ if (app.hasShownUi && clientAdj > PERCEPTIBLE_APP_ADJ) {
+ adjType = "bound-bg-ui-services";
+ } else {
+ if ((cr.flags&(Context.BIND_ABOVE_CLIENT
+ |Context.BIND_IMPORTANT)) != 0) {
+ adj = clientAdj;
+ } else if (clientAdj >= VISIBLE_APP_ADJ) {
+ adj = clientAdj;
+ } else {
+ adj = VISIBLE_APP_ADJ;
+ }
+ if (!client.hidden) {
+ app.hidden = false;
+ }
+ if (client.keeping) {
+ app.keeping = true;
+ }
+ adjType = "service";
}
- adjType = "service";
}
if (adjType != null) {
app.adjType = adjType;
@@ -12848,21 +12907,22 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
}
- ActivityRecord a = cr.activity;
- //if (a != null) {
- // Slog.i(TAG, "Connection to " + a ": state=" + a.state);
- //}
- if (a != null && adj > FOREGROUND_APP_ADJ &&
- (a.state == ActivityState.RESUMED
- || a.state == ActivityState.PAUSING)) {
- adj = FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.hidden = false;
- app.adjType = "service";
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE;
- app.adjSource = a;
- app.adjTarget = s.name;
+ if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
+ ActivityRecord a = cr.activity;
+ if (a != null && adj > FOREGROUND_APP_ADJ &&
+ (a.visible || a.state == ActivityState.RESUMED
+ || a.state == ActivityState.PAUSING)) {
+ adj = FOREGROUND_APP_ADJ;
+ if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ }
+ app.hidden = false;
+ app.adjType = "service";
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE;
+ app.adjSource = a;
+ app.adjTarget = s.name;
+ }
}
}
}
@@ -12906,15 +12966,19 @@ public final class ActivityManagerService extends ActivityManagerNative
int clientAdj = computeOomAdjLocked(
client, myHiddenAdj, TOP_APP, true);
if (adj > clientAdj) {
- adj = clientAdj > FOREGROUND_APP_ADJ
- ? clientAdj : FOREGROUND_APP_ADJ;
+ if (app.hasShownUi && clientAdj > PERCEPTIBLE_APP_ADJ) {
+ app.adjType = "bg-ui-provider";
+ } else {
+ adj = clientAdj > FOREGROUND_APP_ADJ
+ ? clientAdj : FOREGROUND_APP_ADJ;
+ app.adjType = "provider";
+ }
if (!client.hidden) {
app.hidden = false;
}
if (client.keeping) {
app.keeping = true;
}
- app.adjType = "provider";
app.adjTypeCode = ActivityManager.RunningAppProcessInfo
.REASON_PROVIDER_IN_USE;
app.adjSource = client;
@@ -12955,6 +13019,25 @@ public final class ActivityManagerService extends ActivityManagerNative
app.keeping = true;
}
+ if (app.hasAboveClient) {
+ // If this process has bound to any services with BIND_ABOVE_CLIENT,
+ // then we need to drop its adjustment to be lower than the service's
+ // in order to honor the request. We want to drop it by one adjustment
+ // level... but there is special meaning applied to various levels so
+ // we will skip some of them.
+ if (adj < FOREGROUND_APP_ADJ) {
+ // System process will not get dropped, ever
+ } else if (adj < VISIBLE_APP_ADJ) {
+ adj = VISIBLE_APP_ADJ;
+ } else if (adj < PERCEPTIBLE_APP_ADJ) {
+ adj = PERCEPTIBLE_APP_ADJ;
+ } else if (adj < HIDDEN_APP_MIN_ADJ) {
+ adj = HIDDEN_APP_MIN_ADJ;
+ } else if (adj < EMPTY_APP_ADJ) {
+ adj++;
+ }
+ }
+
app.curAdj = adj;
app.curSchedGroup = schedGroup;
@@ -12963,7 +13046,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.foregroundActivities).sendToTarget();
}
- return adj;
+ return app.curRawAdj;
}
/**
@@ -13204,7 +13287,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final boolean wasKeeping = app.keeping;
- int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
+ computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
if (app.curRawAdj != app.setRawAdj) {
if (app.curRawAdj > FOREGROUND_APP_ADJ
@@ -13233,14 +13316,14 @@ public final class ActivityManagerService extends ActivityManagerNative
app.setRawAdj = app.curRawAdj;
}
- if (adj != app.setAdj) {
- if (Process.setOomAdj(app.pid, adj)) {
+ if (app.curAdj != app.setAdj) {
+ if (Process.setOomAdj(app.pid, app.curAdj)) {
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
TAG, "Set app " + app.processName +
- " oom adj to " + adj + " because " + app.adjType);
- app.setAdj = adj;
+ " oom adj to " + app.curAdj + " because " + app.adjType);
+ app.setAdj = app.curAdj;
} else {
- Slog.w(TAG, "Failed setting oom adj of " + app + " to " + adj);
+ Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj);
}
}
if (app.setSchedGroup != app.curSchedGroup) {
@@ -13377,7 +13460,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final int N = mLruProcesses.size();
factor = numBg/3;
step = 0;
- int curLevel = ComponentCallbacks.TRIM_MEMORY_COMPLETE;
+ int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
for (i=0; i<N; i++) {
ProcessRecord app = mLruProcesses.get(i);
if (app.curAdj >= HIDDEN_APP_MIN_ADJ && !app.killedBackground) {
@@ -13386,7 +13469,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.thread.scheduleTrimMemory(curLevel);
} catch (RemoteException e) {
}
- if (curLevel >= ComponentCallbacks.TRIM_MEMORY_COMPLETE) {
+ if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
// For these apps we will also finish their activities
// to help them free memory.
mMainStack.destroyActivitiesLocked(app, false);
@@ -13396,23 +13479,36 @@ public final class ActivityManagerService extends ActivityManagerNative
step++;
if (step >= factor) {
switch (curLevel) {
- case ComponentCallbacks.TRIM_MEMORY_COMPLETE:
- curLevel = ComponentCallbacks.TRIM_MEMORY_MODERATE;
+ case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+ curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
break;
- case ComponentCallbacks.TRIM_MEMORY_MODERATE:
- curLevel = ComponentCallbacks.TRIM_MEMORY_BACKGROUND;
+ case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+ curLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
break;
}
}
} else if (app.curAdj == HEAVY_WEIGHT_APP_ADJ) {
- if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_BACKGROUND
+ if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
&& app.thread != null) {
try {
- app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_BACKGROUND);
+ app.thread.scheduleTrimMemory(
+ ComponentCallbacks2.TRIM_MEMORY_BACKGROUND);
} catch (RemoteException e) {
}
}
- app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_BACKGROUND;
+ app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+ } else if ((app.curAdj > VISIBLE_APP_ADJ || app.systemNoUi)
+ && app.pendingUiClean) {
+ if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
+ && app.thread != null) {
+ try {
+ app.thread.scheduleTrimMemory(
+ ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
+ } catch (RemoteException e) {
+ }
+ }
+ app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+ app.pendingUiClean = false;
} else {
app.trimMemoryLevel = 0;
}
@@ -13421,7 +13517,21 @@ public final class ActivityManagerService extends ActivityManagerNative
final int N = mLruProcesses.size();
for (i=0; i<N; i++) {
ProcessRecord app = mLruProcesses.get(i);
- app.trimMemoryLevel = 0;
+ if ((app.curAdj > VISIBLE_APP_ADJ || app.systemNoUi)
+ && app.pendingUiClean) {
+ if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
+ && app.thread != null) {
+ try {
+ app.thread.scheduleTrimMemory(
+ ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
+ } catch (RemoteException e) {
+ }
+ }
+ app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+ app.pendingUiClean = false;
+ } else {
+ app.trimMemoryLevel = 0;
+ }
}
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index cc58eaf..33b21ab 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -560,6 +560,7 @@ final class ActivityStack {
showAskCompatModeDialogLocked(r);
r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
app.hasShownUi = true;
+ app.pendingUiClean = true;
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
System.identityHashCode(r),
r.info, r.compat, r.icicle, results, newIntents, !andResume,
diff --git a/services/java/com/android/server/am/AppBindRecord.java b/services/java/com/android/server/am/AppBindRecord.java
index 9c57360..f1c54fa 100644
--- a/services/java/com/android/server/am/AppBindRecord.java
+++ b/services/java/com/android/server/am/AppBindRecord.java
@@ -26,7 +26,7 @@ import java.util.Iterator;
class AppBindRecord {
final ServiceRecord service; // The running service.
final IntentBindRecord intent; // The intent we are bound to.
- final ProcessRecord client; // Who has started/bound the service.
+ final ProcessRecord client; // Who has started/bound the service.
final HashSet<ConnectionRecord> connections = new HashSet<ConnectionRecord>();
// All ConnectionRecord for this client.
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 5b59363..a896ce4 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -23,6 +23,7 @@ import android.app.Dialog;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.CompatibilityInfo;
import android.os.Bundle;
@@ -66,7 +67,10 @@ class ProcessRecord {
boolean setIsForeground; // Running foreground UI when last set?
boolean foregroundServices; // Running any services that are foreground?
boolean foregroundActivities; // Running any activities that are foreground?
+ boolean systemNoUi; // This is a system process, but not currently showing UI.
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 bad; // True if disabled in the bad process list
boolean killedBackground; // True when proc has been killed due to too many bg
String waitingToKill; // Process is waiting to be killed when in the bg; reason
@@ -185,8 +189,11 @@ class ProcessRecord {
pw.print(" set="); pw.println(setAdj);
pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
pw.print(" setSchedGroup="); pw.print(setSchedGroup);
+ pw.print(" systemNoUi="); pw.print(systemNoUi);
pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
- pw.print(" hasShownUi="); pw.println(hasShownUi);
+ pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
+ pw.print(" pendingUiClean="); pw.print(pendingUiClean);
+ pw.print(" hasAboveClient="); pw.println(hasAboveClient);
pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground);
pw.print(" foregroundServices="); pw.print(foregroundServices);
pw.print(" forcingToForeground="); pw.println(forcingToForeground);
@@ -307,6 +314,18 @@ class ProcessRecord {
deathRecipient = null;
}
+ void updateHasAboveClientLocked() {
+ hasAboveClient = false;
+ if (connections.size() > 0) {
+ for (ConnectionRecord cr : connections) {
+ if ((cr.flags&Context.BIND_ABOVE_CLIENT) != 0) {
+ hasAboveClient = true;
+ break;
+ }
+ }
+ }
+ }
+
public String toShortString() {
if (shortStringName != null) {
return shortStringName;