[Launcher Jank] Avoid lock contention on AssetManager in all apps preinflate thread
Create a separate context with a separate AssetManager obj.
Bug: 337056120
Flag: NONE
Test: presubmit
Change-Id: Ic6765f7f19b649605aec6a889f8382ee10f929b0
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 1049314..633091d 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -412,6 +412,8 @@
public static <T extends BaseActivity> T fromContext(Context context) {
if (context instanceof BaseActivity) {
return (T) context;
+ } else if (context instanceof ActivityContextDelegate) {
+ return (T) ((ActivityContextDelegate) context).mDelegate;
} else if (context instanceof ContextWrapper) {
return fromContext(((ContextWrapper) context).getBaseContext());
} else {
diff --git a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
index 43027da..6d6b3b6 100644
--- a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
+++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
@@ -26,7 +26,9 @@
import com.android.launcher3.util.CancellableTask
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.Executors.VIEW_PREINFLATION_EXECUTOR
+import com.android.launcher3.util.Themes
import com.android.launcher3.views.ActivityContext
+import com.android.launcher3.views.ActivityContext.ActivityContextDelegate
const val PREINFLATE_ICONS_ROW_COUNT = 4
const val EXTRA_ICONS_COUNT = 2
@@ -52,12 +54,28 @@
return
}
+ // Create a separate context dedicated for all apps preinflation thread. The goal is to
+ // create a separate AssetManager obj internally to avoid lock contention with
+ // AssetManager obj that is associated with the launcher context on the main thread.
+ val allAppsPreInflationContext =
+ ActivityContextDelegate(
+ context.createConfigurationContext(context.resources.configuration),
+ Themes.getActivityThemeRes(context),
+ context
+ )
+
// Because we perform onCreateViewHolder() on worker thread, we need a separate
// adapter/inflator object as they are not thread-safe. Note that the adapter
// just need to perform onCreateViewHolder(parent, VIEW_TYPE_ICON) so it doesn't need
// data source information.
val adapter: RecyclerView.Adapter<BaseAllAppsAdapter.ViewHolder> =
- object : BaseAllAppsAdapter<T>(context, context.appsView.layoutInflater, null, null) {
+ object :
+ BaseAllAppsAdapter<T>(
+ context,
+ context.appsView.layoutInflater.cloneInContext(allAppsPreInflationContext),
+ null,
+ null
+ ) {
override fun setAppsPerRow(appsPerRow: Int) = Unit
override fun getLayoutManager(): RecyclerView.LayoutManager? = null
}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index bf43a22..cfac91a 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -41,6 +41,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
+import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
@@ -515,10 +516,21 @@
static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) {
if (context instanceof ActivityContext) {
return (T) context;
+ } else if (context instanceof ActivityContextDelegate acd) {
+ return (T) acd.mDelegate;
} else if (context instanceof ContextWrapper) {
return lookupContextNoThrow(((ContextWrapper) context).getBaseContext());
} else {
return null;
}
}
+
+ class ActivityContextDelegate extends ContextThemeWrapper {
+ public final ActivityContext mDelegate;
+
+ public ActivityContextDelegate(Context base, int themeResId, ActivityContext delegate) {
+ super(base, themeResId);
+ mDelegate = delegate;
+ }
+ }
}