From 6322c00b7074c1d70437b395d7d5d2172da8b8b9 Mon Sep 17 00:00:00 2001 From: Uwais Ashraf Date: Mon, 20 Jan 2025 23:57:21 +0000 Subject: [PATCH] Add kill switch for ViewPool.initPool. This fixes an issue where, in fast E2E tests, the test can complete before initPool is completed. This results in the ViewPool continuing to create TaskViews and therefore TaskThumbnailViews after RecentsDeps is destroyed. Doing this causes a crash. Stopping the ViewPool.initPool thread before destroying RecentsDeps fixes this. Bug: 390156722 Flag: com.android.launcher3.enable_refactor_task_thumbnail Test: fast E2E tests in presubmit e.g. AllAppsImageTest Change-Id: I0f8801ca75cda383df8ed96077cf1b7178771cb6 --- .../com/android/quickstep/views/RecentsView.java | 7 +++++++ src/com/android/launcher3/util/ViewPool.java | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index e037045020..b764e42d39 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1255,6 +1255,13 @@ public abstract class RecentsView< public void destroy() { Log.d(TAG, "destroy"); if (enableRefactorTaskThumbnail()) { + try { + mTaskViewPool.killOngoingInitializations(); + mGroupedTaskViewPool.killOngoingInitializations(); + mDesktopTaskViewPool.killOngoingInitializations(); + } catch (InterruptedException e) { + Log.e(TAG, "Ongoing initializations could not be killed", e); + } mHelper.onDestroy(); RecentsDependencies.destroy(); } diff --git a/src/com/android/launcher3/util/ViewPool.java b/src/com/android/launcher3/util/ViewPool.java index d1cd30f0d5..16270576da 100644 --- a/src/com/android/launcher3/util/ViewPool.java +++ b/src/com/android/launcher3/util/ViewPool.java @@ -44,6 +44,9 @@ public class ViewPool { private int mCurrentSize = 0; + @Nullable + private Thread mViewPoolInitThread; + public ViewPool(Context context, @Nullable ViewGroup parent, int layoutId, int maxSize, int initialSize) { this(LayoutInflater.from(context).cloneInContext(context), @@ -74,13 +77,15 @@ public class ViewPool { // Inflate views on a non looper thread. This allows us to catch errors like calling // "new Handler()" in constructor easily. - new Thread(() -> { + mViewPoolInitThread = new Thread(() -> { for (int i = 0; i < initialSize; i++) { T view = inflateNewView(inflater); handler.post(() -> addToPool(view)); } Log.d(TAG, "initPool complete"); - }, "ViewPool-init").start(); + mViewPoolInitThread = null; + }, "ViewPool-init"); + mViewPoolInitThread.start(); } @UiThread @@ -117,6 +122,12 @@ public class ViewPool { return (T) inflater.inflate(mLayoutId, mParent, false); } + public void killOngoingInitializations() throws InterruptedException { + if (mViewPoolInitThread != null) { + mViewPoolInitThread.join(); + } + } + /** * Interface to indicate that a view is reusable */