diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-07-29 01:25:18 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2011-07-29 02:06:46 -0700 |
commit | c68c913d357e2955d4bd7ca52829071e531c7825 (patch) | |
tree | 764dddf699a1db5e44d74e94e3f354b9ed61ff71 /core/java/android/app | |
parent | 3970f6833d3c19f96cc7b6831327c8488932fa57 (diff) | |
download | frameworks_base-c68c913d357e2955d4bd7ca52829071e531c7825.zip frameworks_base-c68c913d357e2955d4bd7ca52829071e531c7825.tar.gz frameworks_base-c68c913d357e2955d4bd7ca52829071e531c7825.tar.bz2 |
Various work on out of memory managment.
- Improve how we handle processes that have shown UI, to take care
of more cases where we want to push them into the background LRU
list.
- New trim memory level for when an application that has done UI
is no longer visible to the user.
- Add APIs to get new trim memory callback.
- Add a host of new bind flags to tweak how the system will adjust
the OOM level of the target process.
Change-Id: I23ba354112f411a9f8773a67426b4dff85fa2439
Diffstat (limited to 'core/java/android/app')
-rw-r--r-- | core/java/android/app/Activity.java | 22 | ||||
-rw-r--r-- | core/java/android/app/ActivityThread.java | 32 | ||||
-rw-r--r-- | core/java/android/app/Application.java | 160 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 6 | ||||
-rw-r--r-- | core/java/android/app/Fragment.java | 8 | ||||
-rw-r--r-- | core/java/android/app/FragmentManager.java | 11 | ||||
-rw-r--r-- | core/java/android/app/Service.java | 9 |
7 files changed, 225 insertions, 23 deletions
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 |