Use ashmem backed bitmaps for passing around notifications

Avoids many copies during IPC and duplicate Java heap consumption in
system_server, SystemUI, etc.

Bug: 18386420
Change-Id: Id5ac9406062d472f7848009d65f12131f5f4dac9
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5a0d246..af9decc 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3586,12 +3586,19 @@
          * object.
          */
         public Notification build() {
+            if (mSmallIcon != null) {
+                mSmallIcon.convertToAshmem();
+            }
+            if (mLargeIcon != null) {
+                mLargeIcon.convertToAshmem();
+            }
             mOriginatingUserId = mContext.getUserId();
             mHasThreeLines = hasThreeLines();
 
             Notification n = buildUnstyled();
 
             if (mStyle != null) {
+                mStyle.purgeResources();
                 n = mStyle.buildStyled(n);
             }
 
@@ -3790,6 +3797,8 @@
             return wip;
         }
 
+        public void purgeResources() {}
+
         // The following methods are split out so we can re-create notification partially.
         /**
          * @hide
@@ -3901,8 +3910,18 @@
             return this;
         }
 
-        private RemoteViews makeBigContentView() {
+        @Override
+        public void purgeResources() {
+            super.purgeResources();
+            if (mPicture != null && mPicture.isMutable()) {
+                mPicture = mPicture.createAshmemBitmap();
+            }
+            if (mBigLargeIcon != null) {
+                mBigLargeIcon.convertToAshmem();
+            }
+        }
 
+        private RemoteViews makeBigContentView() {
             // Replace mLargeIcon with mBigLargeIcon if mBigLargeIconSet
             // This covers the following cases:
             //   1. mBigLargeIconSet -> mBigLargeIcon (null or non-null) applies, overrides
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 85db6a1..09386c0 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -109,6 +109,10 @@
         return (Bitmap) mObj1;
     }
 
+    private void setBitmap(Bitmap b) {
+        mObj1 = b;
+    }
+
     /**
      * @return The length of the compressed bitmap byte array held by this {@link #TYPE_DATA} Icon.
      * @hide
@@ -347,6 +351,16 @@
     }
 
     /**
+     * Puts the memory used by this instance into Ashmem memory, if possible.
+     * @hide
+     */
+    public void convertToAshmem() {
+        if (mType == TYPE_BITMAP && getBitmap().isMutable()) {
+            setBitmap(getBitmap().createAshmemBitmap());
+        }
+    }
+
+    /**
      * Writes a serialized version of an Icon to the specified stream.
      *
      * @param stream The stream on which to serialize the Icon.
@@ -466,7 +480,7 @@
             throw new IllegalArgumentException("Bitmap must not be null.");
         }
         final Icon rep = new Icon(TYPE_BITMAP);
-        rep.mObj1 = bits;
+        rep.setBitmap(bits);
         return rep;
     }