Merge "Work on more low memory reporting to apps."
diff --git a/api/current.txt b/api/current.txt
index a4b9f97..1c4190e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2722,6 +2722,7 @@
     method public int getLauncherLargeIconSize();
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
+    method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
     method public android.os.Debug.MemoryInfo[] getProcessMemoryInfo(int[]);
     method public java.util.List<android.app.ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState();
     method public java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException;
@@ -2804,6 +2805,7 @@
     field public int importanceReasonCode;
     field public android.content.ComponentName importanceReasonComponent;
     field public int importanceReasonPid;
+    field public int lastTrimLevel;
     field public int lru;
     field public int pid;
     field public java.lang.String[] pkgList;
@@ -4826,6 +4828,9 @@
     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_RUNNING_CRITICAL = 15; // 0xf
+    field public static final int TRIM_MEMORY_RUNNING_LOW = 10; // 0xa
+    field public static final int TRIM_MEMORY_RUNNING_MODERATE = 5; // 0x5
     field public static final int TRIM_MEMORY_UI_HIDDEN = 20; // 0x14
   }
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d98d87b..59c803e 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1145,7 +1145,14 @@
          * @hide
          */
         public int flags;
-        
+
+        /**
+         * Last memory trim level reported to the process: corresponds to
+         * the values supplied to {@link android.content.ComponentCallbacks2#onTrimMemory(int)
+         * ComponentCallbacks2.onTrimMemory(int)}.
+         */
+        public int lastTrimLevel;
+
         /**
          * Constant for {@link #importance}: this process is running the
          * foreground UI.
@@ -1212,7 +1219,7 @@
          * be maintained in the future.
          */
         public int lru;
-        
+
         /**
          * Constant for {@link #importanceReasonCode}: nothing special has
          * been specified for the reason for this level.
@@ -1282,6 +1289,7 @@
             dest.writeInt(uid);
             dest.writeStringArray(pkgList);
             dest.writeInt(this.flags);
+            dest.writeInt(lastTrimLevel);
             dest.writeInt(importance);
             dest.writeInt(lru);
             dest.writeInt(importanceReasonCode);
@@ -1296,6 +1304,7 @@
             uid = source.readInt();
             pkgList = source.readStringArray();
             flags = source.readInt();
+            lastTrimLevel = source.readInt();
             importance = source.readInt();
             lru = source.readInt();
             importanceReasonCode = source.readInt();
@@ -1349,7 +1358,25 @@
             return null;
         }
     }
-    
+
+    /**
+     * Return global memory state information for the calling process.  This
+     * does not fill in all fields of the {@link RunningAppProcessInfo}.  The
+     * only fields that will be filled in are
+     * {@link RunningAppProcessInfo#pid},
+     * {@link RunningAppProcessInfo#uid},
+     * {@link RunningAppProcessInfo#lastTrimLevel},
+     * {@link RunningAppProcessInfo#importance},
+     * {@link RunningAppProcessInfo#lru}, and
+     * {@link RunningAppProcessInfo#importanceReasonCode}.
+     */
+    static public void getMyMemoryState(RunningAppProcessInfo outState) {
+        try {
+            ActivityManagerNative.getDefault().getMyMemoryState(outState);
+        } catch (RemoteException e) {
+        }
+    }
+
     /**
      * Return information about the memory usage of one or more processes.
      * 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 24079a5d..b952649 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1126,7 +1126,17 @@
             reply.writeNoException();
             return true;
         }
-        
+
+        case GET_MY_MEMORY_STATE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            ActivityManager.RunningAppProcessInfo info =
+                    new ActivityManager.RunningAppProcessInfo();
+            getMyMemoryState(info);
+            reply.writeNoException();
+            info.writeToParcel(reply, 0);
+            return true;
+        }
+
         case GET_DEVICE_CONFIGURATION_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             ConfigurationInfo config = getDeviceConfigurationInfo();
@@ -2973,6 +2983,19 @@
         reply.recycle();
     }
     
+    public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo)
+            throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_MY_MEMORY_STATE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        outInfo.readFromParcel(reply);
+        reply.recycle();
+        data.recycle();
+    }
+
     public ConfigurationInfo getDeviceConfigurationInfo() throws RemoteException
     {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 53a71db..ea2545f 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -278,13 +278,16 @@
      * SIGUSR1 is delivered. All others are ignored.
      */
     public void signalPersistentProcesses(int signal) throws RemoteException;
-    // Retrieve info of applications installed on external media that are currently
-    // running.
+    // Retrieve running application processes in the system
     public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses()
             throws RemoteException;
- // Retrieve running application processes in the system
+    // Retrieve info of applications installed on external media that are currently
+    // running.
     public List<ApplicationInfo> getRunningExternalApplications()
             throws RemoteException;
+    // Get memory information about the calling process.
+    public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo)
+            throws RemoteException;
     // Get device configuration
     public ConfigurationInfo getDeviceConfigurationInfo() throws RemoteException;
     
@@ -606,4 +609,5 @@
     int KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+139;
     int GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+140;
     int REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+141;
+    int GET_MY_MEMORY_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+142;
 }
diff --git a/core/java/android/content/ComponentCallbacks2.java b/core/java/android/content/ComponentCallbacks2.java
index 8b9f97c..85294dd 100644
--- a/core/java/android/content/ComponentCallbacks2.java
+++ b/core/java/android/content/ComponentCallbacks2.java
@@ -52,15 +52,49 @@
     static final int TRIM_MEMORY_UI_HIDDEN = 20;
 
     /**
+     * Level for {@link #onTrimMemory(int)}: the process is not an expendable
+     * background process, but the device is running extremely low on memory
+     * and is about to not be able to keep any background processes running.
+     * Your running process should free up as many non-critical resources as it
+     * can to allow that memory to be used elsewhere.  The next thing that
+     * will happen after this is {@link #onLowMemory()} called to report that
+     * nothing at all can be kept in the background, a situation that can start
+     * to notably impact the user.
+     */
+    static final int TRIM_MEMORY_RUNNING_CRITICAL = 15;
+
+    /**
+     * Level for {@link #onTrimMemory(int)}: the process is not an expendable
+     * background process, but the device is running low on memory.
+     * Your running process should free up unneeded resources to allow that
+     * memory to be used elsewhere.
+     */
+    static final int TRIM_MEMORY_RUNNING_LOW = 10;
+
+
+    /**
+     * Level for {@link #onTrimMemory(int)}: the process is not an expendable
+     * background process, but the device is running moderately low on memory.
+     * Your running process may want to release some unneeded resources for
+     * use elsewhere.
+     */
+    static final int TRIM_MEMORY_RUNNING_MODERATE = 5;
+
+    /**
      * 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.
+     * memory to keep as many background processes running as desired.  You
+     * should never compare to exact values of the level, since new intermediate
+     * values may be added -- you will typically want to compare if the value
+     * is greater or equal to a level you are interested in.
      * 
      * @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}.
+     * {@link #TRIM_MEMORY_BACKGROUND}, {@link #TRIM_MEMORY_UI_HIDDEN},
+     * {@link #TRIM_MEMORY_RUNNING_CRITICAL}, {@link #TRIM_MEMORY_RUNNING_LOW},
+     * or {@link #TRIM_MEMORY_RUNNING_MODERATE}.
      */
     void onTrimMemory(int level);
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index ec95863..bf91700 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1284,15 +1284,10 @@
                 usePbufferSurface(managedContext.getContext());
             }
 
-            switch (level) {
-                case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
-                case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
-                case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
-                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
-                    break;
-                case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
-                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
-                    break;
+            if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
+                GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_FULL);
+            } else if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
+                GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_MODERATE);
             }
         }
 
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index d482b35..0e4a30f 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -432,29 +432,25 @@
      */
     public void trimMemory(int level) {
         if (HardwareRenderer.isAvailable()) {
-            switch (level) {
-                case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
-                case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
-                    // On low and medium end gfx devices
-                    if (!ActivityManager.isHighEndGfx(getDefaultDisplay())) {
-                        // Destroy all hardware surfaces and resources associated to
-                        // known windows
-                        synchronized (this) {
-                            if (mViews == null) return;
-                            int count = mViews.length;
-                            for (int i = 0; i < count; i++) {
-                                mRoots[i].terminateHardwareResources();
-                            }
+            // On low and medium end gfx devices
+            if (!ActivityManager.isHighEndGfx(getDefaultDisplay())) {
+                if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
+                    // Destroy all hardware surfaces and resources associated to
+                    // known windows
+                    synchronized (this) {
+                        if (mViews == null) return;
+                        int count = mViews.length;
+                        for (int i = 0; i < count; i++) {
+                            mRoots[i].terminateHardwareResources();
                         }
-                        // Force a full memory flush
-                        HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
-                        mNeedsEglTerminate = true;
-                        break;
                     }
-                    // high end gfx devices fall through to next case
-                default:
-                    HardwareRenderer.trimMemory(level);
+                    // Force a full memory flush
+                    HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+                    mNeedsEglTerminate = true;
+                    return;
+                }
             }
+            HardwareRenderer.trimMemory(level);
         }
     }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 3ac446c..4ea2f04 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7952,6 +7952,22 @@
         }
     }
 
+    private void fillInProcMemInfo(ProcessRecord app,
+            ActivityManager.RunningAppProcessInfo outInfo) {
+        outInfo.pid = app.pid;
+        outInfo.uid = app.info.uid;
+        if (mHeavyWeightProcess == app) {
+            outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
+        }
+        if (app.persistent) {
+            outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
+        }
+        outInfo.lastTrimLevel = app.trimMemoryLevel;
+        int adj = app.curAdj;
+        outInfo.importance = oomAdjToImportance(adj, outInfo);
+        outInfo.importanceReasonCode = app.adjTypeCode;
+    }
+
     public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
         enforceNotIsolatedCaller("getRunningAppProcesses");
         // Lazy instantiation of list
@@ -7965,16 +7981,7 @@
                     ActivityManager.RunningAppProcessInfo currApp = 
                         new ActivityManager.RunningAppProcessInfo(app.processName,
                                 app.pid, app.getPackageList());
-                    currApp.uid = app.info.uid;
-                    if (mHeavyWeightProcess == app) {
-                        currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
-                    }
-                    if (app.persistent) {
-                        currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
-                    }
-                    int adj = app.curAdj;
-                    currApp.importance = oomAdjToImportance(adj, currApp);
-                    currApp.importanceReasonCode = app.adjTypeCode;
+                    fillInProcMemInfo(app, currApp);
                     if (app.adjSource instanceof ProcessRecord) {
                         currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
                         currApp.importanceReasonImportance = oomAdjToImportance(
@@ -8026,6 +8033,18 @@
     }
 
     @Override
+    public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo) {
+        enforceNotIsolatedCaller("getMyMemoryState");
+        synchronized (this) {
+            ProcessRecord proc;
+            synchronized (mPidsSelfLocked) {
+                proc = mPidsSelfLocked.get(Binder.getCallingPid());
+            }
+            fillInProcMemInfo(proc, outInfo);
+        }
+    }
+
+    @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (checkCallingPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -8479,8 +8498,8 @@
                     pw.print("    Process "); pw.print(pname);
                             pw.print(" uid "); pw.print(puid);
                             pw.print(": last crashed ");
-                            pw.print((now-uids.valueAt(i)));
-                            pw.println(" ms ago");
+                            TimeUtils.formatDuration(now-uids.valueAt(i), pw);
+                            pw.println(" ago");
                 }
             }
         }
@@ -13982,6 +14001,14 @@
             if (mPreviousProcess != null) minFactor++;
             if (factor < minFactor) factor = minFactor;
             step = 0;
+            int fgTrimLevel;
+            if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/5)) {
+                fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
+            } else if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/3)) {
+                fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
+            } else {
+                fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
+            }
             int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
             for (i=0; i<N; i++) {
                 ProcessRecord app = mLruProcesses.get(i);
@@ -14008,6 +14035,7 @@
                     app.trimMemoryLevel = curLevel;
                     step++;
                     if (step >= factor) {
+                        step = 0;
                         switch (curLevel) {
                             case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
                                 curLevel = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
@@ -14027,20 +14055,28 @@
                         }
                     }
                     app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
-                } else if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
-                        && app.pendingUiClean) {
-                    if (app.trimMemoryLevel < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
-                            && app.thread != null) {
+                } else {
+                    if ((app.curAdj > ProcessList.VISIBLE_APP_ADJ || app.systemNoUi)
+                            && app.pendingUiClean) {
+                        // If this application is now in the background and it
+                        // had done UI, then give it the special trim level to
+                        // have it free UI resources.
+                        final int level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+                        if (app.trimMemoryLevel < level && app.thread != null) {
+                            try {
+                                app.thread.scheduleTrimMemory(level);
+                            } catch (RemoteException e) {
+                            }
+                        }
+                        app.pendingUiClean = false;
+                    }
+                    if (app.trimMemoryLevel < fgTrimLevel && app.thread != null) {
                         try {
-                            app.thread.scheduleTrimMemory(
-                                    ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
+                            app.thread.scheduleTrimMemory(fgTrimLevel);
                         } catch (RemoteException e) {
                         }
                     }
-                    app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
-                    app.pendingUiClean = false;
-                } else {
-                    app.trimMemoryLevel = 0;
+                    app.trimMemoryLevel = fgTrimLevel;
                 }
             }
         } else {
@@ -14057,11 +14093,9 @@
                         } catch (RemoteException e) {
                         }
                     }
-                    app.trimMemoryLevel = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
                     app.pendingUiClean = false;
-                } else {
-                    app.trimMemoryLevel = 0;
                 }
+                app.trimMemoryLevel = 0;
             }
         }