diff options
| author | Vadim Caen <caen@google.com> | 2021-05-31 17:20:45 +0200 |
|---|---|---|
| committer | Vadim Caen <caen@google.com> | 2021-06-15 15:39:09 +0200 |
| commit | a46ff113be1c3f2105c4ebb7dbe2e1390ea6c70c (patch) | |
| tree | 3ac79085e75f33e2b3a3aceae43d79413d999723 /core/java/android/window/SplashScreenView.java | |
| parent | 5829bd558ac39c73f2059b6e1ee542de6d6a115f (diff) | |
Release the SurfacePackageViewHost on splash screen removed
The SurfacePackageViewHost was never release, leading to a leak of its
surfaces.
This CL ensure it is released:
- Directly in the shell if the SplashScreenView was not copied
- From the client, through the window manger and then to the shell if
the splash screen was copied in the client process
Test: Manually tested with app setting by checking if the surfaces
are actually removed (winscope + logs) in the following scenarios:
- When the application registers an OnExitAnimationListener
and calls remove(),
- When the application registers an OnExitAnimationListener
and dies without calling remove()
- When the applicaiton does not register an OnExitAnimationListener
and the shell removes the splash screen
Bug: 189759180
Change-Id: Ib68bfffad6720911368739d7dd87d8a03034c589
Diffstat (limited to 'core/java/android/window/SplashScreenView.java')
| -rw-r--r-- | core/java/android/window/SplashScreenView.java | 64 |
1 files changed, 60 insertions, 4 deletions
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java index 6772afeb0270..4a3bf91645f2 100644 --- a/core/java/android/window/SplashScreenView.java +++ b/core/java/android/window/SplashScreenView.java @@ -34,8 +34,10 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.os.RemoteCallback; import android.os.Trace; import android.util.AttributeSet; import android.util.Log; @@ -76,7 +78,7 @@ import java.time.Instant; */ public final class SplashScreenView extends FrameLayout { private static final String TAG = SplashScreenView.class.getSimpleName(); - private static final boolean DEBUG = false; + private static final boolean DEBUG = Build.IS_DEBUGGABLE; private static final int LIGHT_BARS_MASK = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS @@ -85,6 +87,7 @@ public final class SplashScreenView extends FrameLayout { | FLAG_TRANSLUCENT_NAVIGATION | FLAG_TRANSLUCENT_STATUS; private boolean mNotCopyable; + private boolean mIsCopied; private int mInitBackgroundColor; private int mInitIconBackgroundColor; private View mIconView; @@ -103,6 +106,10 @@ public final class SplashScreenView extends FrameLayout { private SurfaceControlViewHost.SurfacePackage mSurfacePackage; @Nullable private SurfaceView mSurfaceView; + @Nullable + private SurfaceControlViewHost mSurfaceHost; + @Nullable + private RemoteCallback mClientCallback; // cache original window and status private Window mWindow; @@ -127,6 +134,7 @@ public final class SplashScreenView extends FrameLayout { private Bitmap mParceledIconBitmap; private Drawable mIconDrawable; private SurfaceControlViewHost.SurfacePackage mSurfacePackage; + private RemoteCallback mClientCallback; private int mBrandingImageWidth; private int mBrandingImageHeight; private Drawable mBrandingDrawable; @@ -161,6 +169,7 @@ public final class SplashScreenView extends FrameLayout { } mIconAnimationStart = Instant.ofEpochMilli(parcelable.mIconAnimationStartMillis); mIconAnimationDuration = Duration.ofMillis(parcelable.mIconAnimationDurationMillis); + mClientCallback = parcelable.mClientCallback; if (DEBUG) { Log.d(TAG, String.format("Building from parcel drawable: %s", mIconDrawable)); } @@ -228,6 +237,7 @@ public final class SplashScreenView extends FrameLayout { view.mInitBackgroundColor = mBackgroundColor; view.mInitIconBackgroundColor = mIconBackground; view.setBackgroundColor(mBackgroundColor); + view.mClientCallback = mClientCallback; view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view); @@ -285,7 +295,8 @@ public final class SplashScreenView extends FrameLayout { if (mSurfacePackage == null) { if (DEBUG) { Log.d(TAG, - "Creating Original SurfacePackage. SurfaceView: " + surfaceView); + "SurfaceControlViewHost created on thread " + + Thread.currentThread().getId()); } SurfaceControlViewHost viewHost = new SurfaceControlViewHost(mContext, @@ -297,6 +308,7 @@ public final class SplashScreenView extends FrameLayout { SurfaceControlViewHost.SurfacePackage surfacePackage = viewHost.getSurfacePackage(); surfaceView.setChildSurfacePackage(surfacePackage); view.mSurfacePackage = surfacePackage; + view.mSurfaceHost = viewHost; view.mSurfacePackageCopy = new SurfaceControlViewHost.SurfacePackage( surfacePackage); } else { @@ -357,6 +369,7 @@ public final class SplashScreenView extends FrameLayout { * @hide */ public void onCopied() { + mIsCopied = true; if (mSurfaceView == null) { return; } @@ -369,6 +382,12 @@ public final class SplashScreenView extends FrameLayout { mSurfacePackage = null; } + /** @hide **/ + @Nullable + public SurfaceControlViewHost getSurfaceHost() { + return mSurfaceHost; + } + @Override public void setAlpha(float alpha) { super.setAlpha(alpha); @@ -407,8 +426,7 @@ public final class SplashScreenView extends FrameLayout { if (DEBUG) { mSurfacePackage.getSurfaceControl().addOnReparentListener( (transaction, parent) -> Log.e(TAG, - String.format("SurfacePackage'surface reparented.\n Parent: %s", - parent), new Throwable())); + String.format("SurfacePackage'surface reparented to %s", parent))); Log.d(TAG, "Transferring surface " + mSurfaceView.toString()); } mSurfaceView.setChildSurfacePackage(mSurfacePackage); @@ -466,9 +484,36 @@ public final class SplashScreenView extends FrameLayout { mHasRemoved = true; } + /** @hide **/ + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + releaseAnimationSurfaceHost(); + } + + private void releaseAnimationSurfaceHost() { + if (mSurfaceHost != null && !mIsCopied) { + final SurfaceControlViewHost finalSurfaceHost = mSurfaceHost; + mSurfaceHost = null; + finalSurfaceHost.getView().post(() -> { + if (DEBUG) { + Log.d(TAG, + "Shell removed splash screen." + + " Releasing SurfaceControlViewHost on thread #" + + Thread.currentThread().getId()); + } + finalSurfaceHost.release(); + }); + } else if (mSurfacePackage != null && mSurfaceHost == null) { + mSurfacePackage = null; + mClientCallback.sendResult(null); + } + } + /** * Called when this view is attached to an activity. This also makes SystemUI colors * transparent so the content of splash screen view can draw fully. + * * @hide */ public void attachHostActivityAndSetSystemUIColors(Activity activity, Window window) { @@ -585,6 +630,7 @@ public final class SplashScreenView extends FrameLayout { private long mIconAnimationDurationMillis; private SurfaceControlViewHost.SurfacePackage mSurfacePackage; + private RemoteCallback mClientCallback; public SplashScreenViewParcelable(SplashScreenView view) { mIconSize = view.mIconView.getWidth(); @@ -641,6 +687,7 @@ public final class SplashScreenView extends FrameLayout { mIconAnimationDurationMillis = source.readLong(); mIconBackground = source.readInt(); mSurfacePackage = source.readTypedObject(SurfaceControlViewHost.SurfacePackage.CREATOR); + mClientCallback = source.readTypedObject(RemoteCallback.CREATOR); } @Override @@ -660,6 +707,7 @@ public final class SplashScreenView extends FrameLayout { dest.writeLong(mIconAnimationDurationMillis); dest.writeInt(mIconBackground); dest.writeTypedObject(mSurfacePackage, flags); + dest.writeTypedObject(mClientCallback, flags); } public static final @NonNull Parcelable.Creator<SplashScreenViewParcelable> CREATOR = @@ -697,5 +745,13 @@ public final class SplashScreenView extends FrameLayout { int getIconBackground() { return mIconBackground; } + + /** + * Sets the {@link RemoteCallback} that will be called by the client to notify the shell + * of the removal of the {@link SplashScreenView}. + */ + public void setClientCallback(@NonNull RemoteCallback clientCallback) { + mClientCallback = clientCallback; + } } } |
