From c817dac4cd5d6b855b3dd0ae21d3cb198791da28 Mon Sep 17 00:00:00 2001 From: Schneider Victor-tulias Date: Mon, 29 Nov 2021 12:23:40 -0800 Subject: [PATCH] Merge ag/16307859 into master without bug fix. - Copied ag/16307859, with a modification to QuickstepModelDelegate#getContainer. This allows the crash from b/173838775 to continue occuring with additional debuging logs. Bug: 173838775 Test: manual Change-Id: Ic96a25665457c80f5c9ab45a896fada34a3a68ff --- .../model/QuickstepModelDelegate.java | 22 ++++- .../android/launcher3/model/BgDataModel.java | 14 +++ .../android/launcher3/model/LoaderCursor.java | 9 +- .../launcher3/model/LoaderMemoryLogger.java | 91 +++++++++++++++++++ .../android/launcher3/model/LoaderTask.java | 29 ++++-- 5 files changed, 152 insertions(+), 13 deletions(-) create mode 100644 src/com/android/launcher3/model/LoaderMemoryLogger.java diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index e82c900734..6ab49f819b 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -161,8 +161,7 @@ public class QuickstepModelDelegate extends ModelDelegate { } InstanceId instanceId = new InstanceIdSequence().newInstanceId(); for (ItemInfo info : itemsIdMap) { - FolderInfo parent = info.container > 0 - ? (FolderInfo) itemsIdMap.get(info.container) : null; + FolderInfo parent = getContainer(info, itemsIdMap); StatsLogCompatManager.writeSnapshot(info.buildProto(parent), instanceId); } additionalSnapshotEvents(instanceId); @@ -199,8 +198,7 @@ public class QuickstepModelDelegate extends ModelDelegate { } for (ItemInfo info : itemsIdMap) { - FolderInfo parent = info.container > 0 - ? (FolderInfo) itemsIdMap.get(info.container) : null; + FolderInfo parent = getContainer(info, itemsIdMap); LauncherAtom.ItemInfo itemInfo = info.buildProto(parent); Log.d(TAG, itemInfo.toString()); StatsEvent statsEvent = StatsLogCompatManager.buildStatsEvent(itemInfo, @@ -222,6 +220,22 @@ public class QuickstepModelDelegate extends ModelDelegate { } } + private static FolderInfo getContainer(ItemInfo info, IntSparseArrayMap itemsIdMap) { + if (info.container > 0) { + ItemInfo containerInfo = itemsIdMap.get(info.container); + + if (!(containerInfo instanceof FolderInfo)) { + Log.e(TAG, String.format( + "Item info: %s found with invalid container: %s", + info, + containerInfo)); + } + // Allow crash to help debug b/173838775 + return (FolderInfo) containerInfo; + } + return null; + } + @Override public void validateData() { super.validateData(); diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 13ad90e302..84612def6c 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -31,6 +31,8 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import androidx.annotation.Nullable; + import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Workspace; @@ -215,6 +217,18 @@ public class BgDataModel { } public synchronized void addItem(Context context, ItemInfo item, boolean newItem) { + addItem(context, item, newItem, null); + } + + public synchronized void addItem( + Context context, ItemInfo item, boolean newItem, @Nullable LoaderMemoryLogger logger) { + if (logger != null) { + logger.addLog( + Log.DEBUG, + TAG, + String.format("Adding item to ID map: %s", item.toString()), + /* stackTrace= */ null); + } itemsIdMap.put(item.id, item); switch (item.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 47df53810c..08b38e88ac 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -383,18 +383,23 @@ public class LoaderCursor extends CursorWrapper { info.cellY = getInt(cellYIndex); } + public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) { + checkAndAddItem(info, dataModel, null); + } + /** * Adds the {@param info} to {@param dataModel} if it does not overlap with any other item, * otherwise marks it for deletion. */ - public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) { + public void checkAndAddItem( + ItemInfo info, BgDataModel dataModel, LoaderMemoryLogger logger) { if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { // Ensure that it is a valid intent. An exception here will // cause the item loading to get skipped ShortcutKey.fromItemInfo(info); } if (checkItemPlacement(info)) { - dataModel.addItem(mContext, info, false); + dataModel.addItem(mContext, info, false, logger); } else { markDeleted("Item position overlap"); } diff --git a/src/com/android/launcher3/model/LoaderMemoryLogger.java b/src/com/android/launcher3/model/LoaderMemoryLogger.java new file mode 100644 index 0000000000..f48efcb4a0 --- /dev/null +++ b/src/com/android/launcher3/model/LoaderMemoryLogger.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.model; + +import android.util.Log; + +import androidx.annotation.Nullable; + +import java.util.ArrayList; + +/** + * Helper logger that collects logs while {@code LoaderTask#run} executes and prints them all iff + * an exception is caught in {@code LoaderTask#run}. + */ +public class LoaderMemoryLogger { + + private static final String TAG = "LoaderMemoryLogger"; + + private final ArrayList mLogEntries = new ArrayList<>(); + + protected LoaderMemoryLogger() {} + + protected void addLog(int logLevel, String tag, String log) { + addLog(logLevel, tag, log, null); + } + + protected void addLog( + int logLevel, String tag, String log, Exception stackTrace) { + switch (logLevel) { + case Log.ASSERT: + case Log.ERROR: + case Log.DEBUG: + case Log.INFO: + case Log.VERBOSE: + case Log.WARN: + mLogEntries.add(new LogEntry(logLevel, tag, log, stackTrace)); + break; + default: + throw new IllegalArgumentException("Invalid log level provided: " + logLevel); + + } + } + + protected void clearLogs() { + mLogEntries.clear(); + } + + protected void printLogs() { + for (LogEntry logEntry : mLogEntries) { + String tag = String.format("%s: %s", TAG, logEntry.mLogTag); + String logString = logEntry.mStackStrace == null + ? logEntry.mLogString + : String.format( + "%s\n%s", + logEntry.mLogString, + Log.getStackTraceString(logEntry.mStackStrace)); + + Log.println(logEntry.mLogLevel, tag, logString); + } + clearLogs(); + } + + private static class LogEntry { + + protected final int mLogLevel; + protected final String mLogTag; + protected final String mLogString; + @Nullable protected final Exception mStackStrace; + + protected LogEntry( + int logLevel, String logTag, String logString, @Nullable Exception stackStrace) { + mLogLevel = logLevel; + mLogTag = logTag; + mLogString = logString; + mStackStrace = stackStrace; + } + } +} diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index a4f6f7aa69..2a0f9a6f67 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -52,6 +52,8 @@ import android.util.Log; import android.util.LongSparseArray; import android.util.TimingLogger; +import androidx.annotation.Nullable; + import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; @@ -197,11 +199,12 @@ public class LoaderTask implements Runnable { Object traceToken = TraceHelper.INSTANCE.beginSection(TAG); TimingLogger logger = new TimingLogger(TAG, "run"); + LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger(); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { List allShortcuts = new ArrayList<>(); Trace.beginSection("LoadWorkspace"); try { - loadWorkspace(allShortcuts); + loadWorkspace(allShortcuts, memoryLogger); } finally { Trace.endSection(); } @@ -311,9 +314,13 @@ public class LoaderTask implements Runnable { mModelDelegate.modelLoadComplete(); transaction.commit(); + memoryLogger.clearLogs(); } catch (CancellationException e) { // Loader stopped, ignore logASplit(logger, "Cancelled"); + } catch (Exception e) { + memoryLogger.printLogs(); + throw e; } finally { logger.dumpToLog(); } @@ -325,13 +332,21 @@ public class LoaderTask implements Runnable { this.notify(); } - private void loadWorkspace(List allDeepShortcuts) { + private void loadWorkspace(List allDeepShortcuts, LoaderMemoryLogger logger) { loadWorkspace(allDeepShortcuts, LauncherSettings.Favorites.CONTENT_URI, - null /* selection */); + null /* selection */, logger); } - protected void loadWorkspace(List allDeepShortcuts, Uri contentUri, - String selection) { + protected void loadWorkspace( + List allDeepShortcuts, Uri contentUri, String selection) { + loadWorkspace(allDeepShortcuts, contentUri, selection, null); + } + + protected void loadWorkspace( + List allDeepShortcuts, + Uri contentUri, + String selection, + @Nullable LoaderMemoryLogger logger) { final Context context = mApp.getContext(); final ContentResolver contentResolver = context.getContentResolver(); final PackageManagerHelper pmHelper = new PackageManagerHelper(context); @@ -635,7 +650,7 @@ public class LoaderTask implements Runnable { } } - c.checkAndAddItem(info, mBgDataModel); + c.checkAndAddItem(info, mBgDataModel, logger); } else { throw new RuntimeException("Unexpected null WorkspaceItemInfo"); } @@ -654,7 +669,7 @@ public class LoaderTask implements Runnable { // no special handling required for restored folders c.markRestored(); - c.checkAndAddItem(folderInfo, mBgDataModel); + c.checkAndAddItem(folderInfo, mBgDataModel, logger); break; case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: