From 4df25f7aae05536d3f5dae823a76bae6ddcb9e66 Mon Sep 17 00:00:00 2001 From: Yunfan Chen Date: Wed, 5 Feb 2020 14:48:26 +0900 Subject: [PATCH] Do not write recycled icon to TaskDescription parcel This change prevent the recycled icon from writting to parcel. Some app may recycle their icon while launch a new activity. Parceling tests is added for TaskDescription. Bug: 145504793 Test: Manual test with the reproduce steps in the bug. Test: atest ActivityManagerTest:testTaskDescriptionParceling Change-Id: Ib3bbfe6379419a0763c4d9da00cbd6670e488e1c --- core/java/android/app/ActivityManager.java | 2 +- .../app/activity/ActivityManagerTest.java | 140 ++++++++++++------ 2 files changed, 94 insertions(+), 48 deletions(-) diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 206c7710c12fa..db9aa18dbd5a3 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1472,7 +1472,7 @@ public class ActivityManager { dest.writeInt(1); dest.writeString(mLabel); } - if (mIcon == null) { + if (mIcon == null || mIcon.isRecycled()) { dest.writeInt(0); } else { dest.writeInt(1); diff --git a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java index 6c5d5485664e6..02be557c01bdc 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityManagerTest.java @@ -24,6 +24,9 @@ import android.app.ActivityManager.TaskDescription; import android.content.Context; import android.content.pm.ConfigurationInfo; import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; import android.test.AndroidTestCase; import androidx.test.filters.SmallTest; @@ -137,21 +140,7 @@ public class ActivityManagerTest extends AndroidTestCase { // Must overwrite all the fields td2.copyFrom(td1); - assertEquals(td1.getLabel(), td2.getLabel()); - assertEquals(td1.getInMemoryIcon(), td2.getInMemoryIcon()); - assertEquals(td1.getIconFilename(), td2.getIconFilename()); - assertEquals(td1.getIconResource(), td2.getIconResource()); - assertEquals(td1.getPrimaryColor(), td2.getPrimaryColor()); - assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor()); - assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor()); - assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor()); - assertEquals(td1.getEnsureStatusBarContrastWhenTransparent(), - td2.getEnsureStatusBarContrastWhenTransparent()); - assertEquals(td1.getEnsureNavigationBarContrastWhenTransparent(), - td2.getEnsureNavigationBarContrastWhenTransparent()); - assertEquals(td1.getResizeMode(), td2.getResizeMode()); - assertEquals(td1.getMinWidth(), td2.getMinWidth()); - assertEquals(td1.getMinHeight(), td2.getMinHeight()); + assertTaskDescriptionEqual(td1, td2, true, true); } @SmallTest @@ -191,44 +180,101 @@ public class ActivityManagerTest extends AndroidTestCase { // Must overwrite all public and hidden fields, since other has all fields set. td2.copyFromPreserveHiddenFields(td1); - assertEquals(td1.getLabel(), td2.getLabel()); - assertEquals(td1.getInMemoryIcon(), td2.getInMemoryIcon()); - assertEquals(td1.getIconFilename(), td2.getIconFilename()); - assertEquals(td1.getIconResource(), td2.getIconResource()); - assertEquals(td1.getPrimaryColor(), td2.getPrimaryColor()); - assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor()); - assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor()); - assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor()); - assertEquals(td1.getEnsureStatusBarContrastWhenTransparent(), - td2.getEnsureStatusBarContrastWhenTransparent()); - assertEquals(td1.getEnsureNavigationBarContrastWhenTransparent(), - td2.getEnsureNavigationBarContrastWhenTransparent()); - assertEquals(td1.getResizeMode(), td2.getResizeMode()); - assertEquals(td1.getMinWidth(), td2.getMinWidth()); - assertEquals(td1.getMinHeight(), td2.getMinHeight()); + assertTaskDescriptionEqual(td1, td2, true, true); TaskDescription td3 = new TaskDescription(); // Must overwrite only public fields, and preserve hidden fields. td2.copyFromPreserveHiddenFields(td3); - // Overwritten fields - assertEquals(td3.getLabel(), td2.getLabel()); - assertEquals(td3.getInMemoryIcon(), td2.getInMemoryIcon()); - assertEquals(td3.getIconFilename(), td2.getIconFilename()); - assertEquals(td3.getIconResource(), td2.getIconResource()); - assertEquals(td3.getPrimaryColor(), td2.getPrimaryColor()); - assertEquals(td3.getEnsureStatusBarContrastWhenTransparent(), - td2.getEnsureStatusBarContrastWhenTransparent()); - assertEquals(td3.getEnsureNavigationBarContrastWhenTransparent(), - td2.getEnsureNavigationBarContrastWhenTransparent()); + assertTaskDescriptionEqual(td3, td2, true, false); + assertTaskDescriptionEqual(td1, td2, false, true); + } - // Preserved fields - assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor()); - assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor()); - assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor()); - assertEquals(td1.getResizeMode(), td2.getResizeMode()); - assertEquals(td1.getMinWidth(), td2.getMinWidth()); - assertEquals(td1.getMinHeight(), td2.getMinHeight()); + @SmallTest + public void testTaskDescriptionParceling() throws Exception { + TaskDescription tdBitmapNull = new TaskDescription( + "test label", // label + null, // bitmap + 21, // iconRes + "dummy file", // iconFilename + 0x111111, // colorPrimary + 0x222222, // colorBackground + 0x333333, // statusBarColor + 0x444444, // navigationBarColor + false, // ensureStatusBarContrastWhenTransparent + false, // ensureNavigationBarContrastWhenTransparent + RESIZE_MODE_UNRESIZEABLE, // resizeMode + 10, // minWidth + 20 // minHeight + ); + + // Normal parceling should keep everything the same. + TaskDescription tdParcelled = new TaskDescription(parcelingRoundTrip(tdBitmapNull)); + assertTaskDescriptionEqual(tdBitmapNull, tdParcelled, true, true); + + Bitmap recycledBitmap = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888); + recycledBitmap.recycle(); + assertTrue(recycledBitmap.isRecycled()); + TaskDescription tdBitmapRecycled = new TaskDescription( + "test label", // label + recycledBitmap, // bitmap + 21, // iconRes + "dummy file", // iconFilename + 0x111111, // colorPrimary + 0x222222, // colorBackground + 0x333333, // statusBarColor + 0x444444, // navigationBarColor + false, // ensureStatusBarContrastWhenTransparent + false, // ensureNavigationBarContrastWhenTransparent + RESIZE_MODE_UNRESIZEABLE, // resizeMode + 10, // minWidth + 20 // minHeight + ); + // Recycled bitmap will be ignored while parceling. + tdParcelled = new TaskDescription(parcelingRoundTrip(tdBitmapRecycled)); + assertTaskDescriptionEqual(tdBitmapNull, tdParcelled, true, true); + + } + + private void assertTaskDescriptionEqual(TaskDescription td1, TaskDescription td2, + boolean checkOverwrittenFields, boolean checkPreservedFields) { + if (checkOverwrittenFields) { + assertEquals(td1.getLabel(), td2.getLabel()); + assertEquals(td1.getInMemoryIcon(), td2.getInMemoryIcon()); + assertEquals(td1.getIconFilename(), td2.getIconFilename()); + assertEquals(td1.getIconResource(), td2.getIconResource()); + assertEquals(td1.getPrimaryColor(), td2.getPrimaryColor()); + assertEquals(td1.getEnsureStatusBarContrastWhenTransparent(), + td2.getEnsureStatusBarContrastWhenTransparent()); + assertEquals(td1.getEnsureNavigationBarContrastWhenTransparent(), + td2.getEnsureNavigationBarContrastWhenTransparent()); + } + if (checkPreservedFields) { + assertEquals(td1.getBackgroundColor(), td2.getBackgroundColor()); + assertEquals(td1.getStatusBarColor(), td2.getStatusBarColor()); + assertEquals(td1.getNavigationBarColor(), td2.getNavigationBarColor()); + assertEquals(td1.getResizeMode(), td2.getResizeMode()); + assertEquals(td1.getMinWidth(), td2.getMinWidth()); + assertEquals(td1.getMinHeight(), td2.getMinHeight()); + } + } + + private T parcelingRoundTrip(final T in) throws Exception { + final Parcel p = Parcel.obtain(); + in.writeToParcel(p, /* flags */ 0); + p.setDataPosition(0); + final byte[] marshalledData = p.marshall(); + p.recycle(); + + final Parcel q = Parcel.obtain(); + q.unmarshall(marshalledData, 0, marshalledData.length); + q.setDataPosition(0); + + final Parcelable.Creator creator = (Parcelable.Creator) + in.getClass().getField("CREATOR").get(null); // static object, so null receiver + final T unmarshalled = (T) creator.createFromParcel(q); + q.recycle(); + return unmarshalled; } // If any entries in appear in the list, sanity check them against all running applications