From 2e4477accbe2d681a8d818088eaca9d2eb48c95b Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 25 Apr 2019 07:05:41 -0700 Subject: [PATCH] Filling in content values on the worker thread Writing to disk hapens on the worker thread, so if we create content values on UI thread, some values can change before it is written to disk. This happens in case of shortcuts, where the badge is applied after the icon is queued, but before it is written Bug: 131303610 Change-Id: Ic35b17071d4ed3e5c5fee9f003a225e4ffdc74f3 --- .../android/launcher3/model/ModelWriter.java | 62 ++++++++++--------- src/com/android/launcher3/util/IOUtils.java | 25 ++++++++ 2 files changed, 57 insertions(+), 30 deletions(-) diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java index 40c914b216..4ce2f4ba99 100644 --- a/src/com/android/launcher3/model/ModelWriter.java +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -47,6 +47,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.Executor; +import java.util.function.Supplier; /** * Class for handling model updates. @@ -151,15 +152,13 @@ public class ModelWriter { public void moveItemInDatabase(final ItemInfo item, int container, int screenId, int cellX, int cellY) { updateItemInfoProps(item, container, screenId, cellX, cellY); - - final ContentWriter writer = new ContentWriter(mContext) - .put(Favorites.CONTAINER, item.container) - .put(Favorites.CELLX, item.cellX) - .put(Favorites.CELLY, item.cellY) - .put(Favorites.RANK, item.rank) - .put(Favorites.SCREEN, item.screenId); - - enqueueDeleteRunnable(new UpdateItemRunnable(item, writer)); + enqueueDeleteRunnable(new UpdateItemRunnable(item, () -> + new ContentWriter(mContext) + .put(Favorites.CONTAINER, item.container) + .put(Favorites.CELLX, item.cellX) + .put(Favorites.CELLY, item.cellY) + .put(Favorites.RANK, item.rank) + .put(Favorites.SCREEN, item.screenId))); } /** @@ -195,25 +194,26 @@ public class ModelWriter { item.spanX = spanX; item.spanY = spanY; - final ContentWriter writer = new ContentWriter(mContext) - .put(Favorites.CONTAINER, item.container) - .put(Favorites.CELLX, item.cellX) - .put(Favorites.CELLY, item.cellY) - .put(Favorites.RANK, item.rank) - .put(Favorites.SPANX, item.spanX) - .put(Favorites.SPANY, item.spanY) - .put(Favorites.SCREEN, item.screenId); - - mWorkerExecutor.execute(new UpdateItemRunnable(item, writer)); + mWorkerExecutor.execute(new UpdateItemRunnable(item, () -> + new ContentWriter(mContext) + .put(Favorites.CONTAINER, item.container) + .put(Favorites.CELLX, item.cellX) + .put(Favorites.CELLY, item.cellY) + .put(Favorites.RANK, item.rank) + .put(Favorites.SPANX, item.spanX) + .put(Favorites.SPANY, item.spanY) + .put(Favorites.SCREEN, item.screenId))); } /** * Update an item to the database in a specified container. */ public void updateItemInDatabase(ItemInfo item) { - ContentWriter writer = new ContentWriter(mContext); - item.onAddToDatabase(writer); - mWorkerExecutor.execute(new UpdateItemRunnable(item, writer)); + mWorkerExecutor.execute(new UpdateItemRunnable(item, () -> { + ContentWriter writer = new ContentWriter(mContext); + item.onAddToDatabase(writer); + return writer; + })); } /** @@ -224,17 +224,18 @@ public class ModelWriter { int container, int screenId, int cellX, int cellY) { updateItemInfoProps(item, container, screenId, cellX, cellY); - final ContentWriter writer = new ContentWriter(mContext); final ContentResolver cr = mContext.getContentResolver(); - item.onAddToDatabase(writer); - item.id = Settings.call(cr, Settings.METHOD_NEW_ITEM_ID).getInt(Settings.EXTRA_VALUE); - writer.put(Favorites._ID, item.id); ModelVerifier verifier = new ModelVerifier(); - final StackTraceElement[] stackTrace = new Throwable().getStackTrace(); mWorkerExecutor.execute(() -> { + // Write the item on background thread, as some properties might have been updated in + // the background. + final ContentWriter writer = new ContentWriter(mContext); + item.onAddToDatabase(writer); + writer.put(Favorites._ID, item.id); + cr.insert(Favorites.CONTENT_URI, writer.getValues(mContext)); synchronized (mBgDataModel) { @@ -354,10 +355,10 @@ public class ModelWriter { private class UpdateItemRunnable extends UpdateItemBaseRunnable { private final ItemInfo mItem; - private final ContentWriter mWriter; + private final Supplier mWriter; private final int mItemId; - UpdateItemRunnable(ItemInfo item, ContentWriter writer) { + UpdateItemRunnable(ItemInfo item, Supplier writer) { mItem = item; mWriter = writer; mItemId = item.id; @@ -366,7 +367,8 @@ public class ModelWriter { @Override public void run() { Uri uri = Favorites.getContentUri(mItemId); - mContext.getContentResolver().update(uri, mWriter.getValues(mContext), null, null); + mContext.getContentResolver().update(uri, mWriter.get().getValues(mContext), + null, null); updateItemArrays(mItem, mItemId); } } diff --git a/src/com/android/launcher3/util/IOUtils.java b/src/com/android/launcher3/util/IOUtils.java index 77c21fe925..f95f74d600 100644 --- a/src/com/android/launcher3/util/IOUtils.java +++ b/src/com/android/launcher3/util/IOUtils.java @@ -16,12 +16,18 @@ package com.android.launcher3.util; +import android.content.Context; + +import com.android.launcher3.config.FeatureFlags; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.UUID; /** * Supports various IO utility functions @@ -52,4 +58,23 @@ public class IOUtils { } return total; } + + /** + * Utility method to debug binary data + */ + public static String createTempFile(Context context, byte[] data) { + if (!FeatureFlags.IS_DOGFOOD_BUILD) { + throw new IllegalStateException("Method only allowed in development mode"); + } + + String name = UUID.randomUUID().toString(); + File file = new File(context.getCacheDir(), name); + try (FileOutputStream fo = new FileOutputStream(file)) { + fo.write(data); + fo.flush(); + } catch (Exception e) { + throw new RuntimeException(e); + } + return file.getAbsolutePath(); + } }