diff options
-rw-r--r-- | api/current.txt | 42 | ||||
-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 | ||||
-rw-r--r-- | core/java/android/content/ComponentCallbacks.java | 9 | ||||
-rw-r--r-- | core/java/android/content/ComponentCallbacks2.java | 66 | ||||
-rw-r--r-- | core/java/android/content/ContentProvider.java | 5 | ||||
-rw-r--r-- | core/java/android/content/Context.java | 82 | ||||
-rw-r--r-- | core/java/android/view/HardwareRenderer.java | 6 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 3 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 222 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityStack.java | 1 | ||||
-rw-r--r-- | services/java/com/android/server/am/AppBindRecord.java | 2 | ||||
-rw-r--r-- | services/java/com/android/server/am/ProcessRecord.java | 21 |
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; |