From 425bfa320f3275803f64dc50637150c6683c56f9 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 24 May 2022 08:55:43 -0700 Subject: [PATCH] Fixing ConcurrentModificationException in FirstScreenBroadcast Bug: 232333237 Test: Not sure, unable to reproduce Change-Id: I3eeabf76c14651d2fb64c82955851efa883760ce --- .../launcher3/model/FirstScreenBroadcast.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java index 5fac7cfcec..9e91b9d6e8 100644 --- a/src/com/android/launcher3/model/FirstScreenBroadcast.java +++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java @@ -20,6 +20,7 @@ import static android.app.PendingIntent.FLAG_ONE_SHOT; import static android.os.Process.myUserHandle; import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.mapping; @@ -31,13 +32,18 @@ import android.content.pm.PackageInstaller.SessionInfo; import android.os.UserHandle; import android.util.Log; +import androidx.annotation.AnyThread; +import androidx.annotation.WorkerThread; + import com.android.launcher3.LauncherSettings; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; +import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -78,6 +84,7 @@ public class FirstScreenBroadcast { * Sends a broadcast to all package installers that have items with active sessions on the users * first screen. */ + @WorkerThread public void sendBroadcasts(Context context, List firstScreenItems) { UserHandle myUser = myUserHandle(); mSessionInfoForPackage @@ -95,6 +102,7 @@ public class FirstScreenBroadcast { * @param packages List of packages with active sessions for this package installer. * @param firstScreenItems List of items on the first screen. */ + @WorkerThread private void sendBroadcastToInstaller(Context context, String installerPackageName, Set packages, List firstScreenItems) { Set folderItems = new HashSet<>(); @@ -106,7 +114,7 @@ public class FirstScreenBroadcast { if (info instanceof FolderInfo) { FolderInfo folderInfo = (FolderInfo) info; String folderItemInfoPackage; - for (ItemInfo folderItemInfo : folderInfo.contents) { + for (ItemInfo folderItemInfo : cloneOnMainThread(folderInfo.contents)) { folderItemInfoPackage = getPackageName(folderItemInfo); if (folderItemInfoPackage != null && packages.contains(folderItemInfoPackage)) { @@ -170,4 +178,17 @@ public class FirstScreenBroadcast { Log.d(TAG, packageInstaller + ":" + label + ":" + pkg); } } + + /** + * Clone the provided list on UI thread. This is used for {@link FolderInfo#contents} which + * is always modified on UI thread. + */ + @AnyThread + private static List cloneOnMainThread(ArrayList list) { + try { + return MAIN_EXECUTOR.submit(() -> new ArrayList(list)).get(); + } catch (Exception e) { + return Collections.emptyList(); + } + } }